package org.example.generator;

import lombok.extern.slf4j.Slf4j;
import org.example.entity.CustomerInfo;
import org.example.entity.CustomerOrder;
import org.example.entity.CustomerRepayPlan;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicInteger;

import org.example.service.CustomerInfoService;
import org.example.service.CustomerOrderService;
import org.example.service.CustomerRepayPlanService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.example.mapper.CustomerInfoMapper;
import org.example.mapper.CustomerOrderMapper;
import org.example.mapper.CustomerRepayPlanMapper;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.transaction.annotation.Transactional;

/**
 * 数据生成器 - 重新设计版本
 * 满足以下要求：
 * 1. 总量20亿在途贷款余额，总投放50亿放款金额
 * 2. 浩瀚小贷在途余额不超过6亿
 * 3. 2023年7月开始放款，前6个月只有浩瀚小贷，后面多产品分布
 * 4. 盈峰小贷占30%，浩瀚小贷占50%，新网银行和江山小贷占20%
 * 5. 每月放款数据递增
 * 6. Vintage逾期率5%左右，迁徙率小于100%
 * 7. 支持批量插入数据库，每2000条批量插入一次
 */
@Component
@Slf4j
public class DataGenerator {
    private static final AtomicLong customerIdCounter = new AtomicLong(System.currentTimeMillis() * 10000);

    @Autowired
    private CustomerInfoMapper customerInfoMapper;

    @Autowired
    private CustomerOrderMapper customerOrderMapper;

    @Autowired
    private CustomerRepayPlanMapper customerRepayPlanMapper;

    @Autowired
    private SqlSessionTemplate sqlSessionTemplate;
    @Autowired
    private CustomerInfoService customerInfoService;

    @Autowired
    private CustomerOrderService customerOrderService;

    @Autowired
    private CustomerRepayPlanService customerRepayPlanService;

    // 数据生成配置
    private static final BigDecimal TARGET_OUTSTANDING_AMOUNT = new BigDecimal("2000000000"); // 20亿在途余额
    private static final BigDecimal TARGET_LOAN_AMOUNT = new BigDecimal("5000000000"); // 50亿总投放
    private static final BigDecimal HAOHAN_MAX_OUTSTANDING = new BigDecimal("600000000"); // 浩瀚小贷最大在途余额6亿
    private static final int BATCH_SIZE = 2000; // 批量插入大小
    private static final LocalDate START_DATE = LocalDate.of(2023, 7, 1); // 2023年7月开始
    private static final int HAOHAN_ONLY_MONTHS = 6; // 前6个月只有浩瀚小贷
    private static final int THREAD_POOL_SIZE = 10; // 线程池大小

    // Vintage配置 - 基于真实业务数据的波状图模式（降低逾期率到5%左右）
    private static final double FIRST_PERIOD_OVERDUE_RATE = 0.0001; // 第一期存在逾期（调整到0.01%）
    private static final double PEAK_OVERDUE_RATE = 0.001; // 峰值逾期率（调整到0.1%）
    private static final double NORMAL_REPAY_WITHIN_3_DAYS_RATE = 0.95; // 95%在3天内正常还款
    private static final double OVERDUE_AFTER_REPAY_RATE = 0.02; // 2%逾期后还款（降低）


    // 城市列表（排除西藏、新疆、甘肃、青海）
    private static final String[] CITIES = {
            // 直辖市
            "北京市", "上海市", "天津市", "重庆市",

            // 河北省
            "石家庄市", "唐山市", "秦皇岛市", "邯郸市", "邢台市", "保定市", "张家口市", "承德市", "沧州市", "廊坊市", "衡水市",

            // 山西省
            "太原市", "大同市", "阳泉市", "长治市", "晋城市", "朔州市", "晋中市", "运城市", "忻州市", "临汾市", "吕梁市",

            // 内蒙古自治区
            "呼和浩特市", "包头市", "乌海市", "赤峰市", "通辽市", "鄂尔多斯市", "呼伦贝尔市", "巴彦淖尔市", "乌兰察布市", "兴安盟", "锡林郭勒盟", "阿拉善盟",

            // 辽宁省
            "沈阳市", "大连市", "鞍山市", "抚顺市", "本溪市", "丹东市", "锦州市", "营口市", "阜新市", "辽阳市", "盘锦市", "铁岭市", "朝阳市", "葫芦岛市",

            // 吉林省
            "长春市", "吉林市", "四平市", "辽源市", "通化市", "白山市", "松原市", "白城市", "延边朝鲜族自治州",

            // 黑龙江省
            "哈尔滨市", "齐齐哈尔市", "鸡西市", "鹤岗市", "双鸭山市", "大庆市", "伊春市", "佳木斯市", "七台河市", "牡丹江市", "黑河市", "绥化市", "大兴安岭地区",

            // 江苏省
            "南京市", "无锡市", "徐州市", "常州市", "苏州市", "南通市", "连云港市", "淮安市", "盐城市", "扬州市", "镇江市", "泰州市", "宿迁市",

            // 浙江省
            "杭州市", "宁波市", "温州市", "嘉兴市", "湖州市", "绍兴市", "金华市", "衢州市", "舟山市", "台州市", "丽水市",

            // 安徽省
            "合肥市", "芜湖市", "蚌埠市", "淮南市", "马鞍山市", "淮北市", "铜陵市", "安庆市", "黄山市", "滁州市", "阜阳市", "宿州市", "六安市", "亳州市", "池州市", "宣城市",

            // 福建省
            "福州市", "厦门市", "莆田市", "三明市", "泉州市", "漳州市", "南平市", "龙岩市", "宁德市",

            // 江西省
            "南昌市", "景德镇市", "萍乡市", "九江市", "新余市", "鹰潭市", "赣州市", "吉安市", "宜春市", "抚州市", "上饶市",

            // 山东省
            "济南市", "青岛市", "淄博市", "枣庄市", "东营市", "烟台市", "潍坊市", "济宁市", "泰安市", "威海市", "日照市", "临沂市", "德州市", "聊城市", "滨州市", "菏泽市",

            // 河南省
            "郑州市", "开封市", "洛阳市", "平顶山市", "安阳市", "鹤壁市", "新乡市", "焦作市", "濮阳市", "许昌市", "漯河市", "三门峡市", "南阳市", "商丘市", "信阳市", "周口市", "驻马店市", "济源市",

            // 湖北省
            "武汉市", "黄石市", "十堰市", "宜昌市", "襄阳市", "鄂州市", "荆门市", "孝感市", "荆州市", "黄冈市", "咸宁市", "随州市", "恩施土家族苗族自治州", "仙桃市", "潜江市", "天门市", "神农架林区",

            // 湖南省
            "长沙市", "株洲市", "湘潭市", "衡阳市", "邵阳市", "岳阳市", "常德市", "张家界市", "益阳市", "郴州市", "永州市", "怀化市", "娄底市", "湘西土家族苗族自治州",

            // 广东省
            "广州市", "韶关市", "深圳市", "珠海市", "汕头市", "佛山市", "江门市", "湛江市", "茂名市", "肇庆市", "惠州市", "梅州市", "汕尾市", "河源市", "阳江市", "清远市", "东莞市", "中山市", "潮州市", "揭阳市", "云浮市",

            // 广西壮族自治区
            "南宁市", "柳州市", "桂林市", "梧州市", "北海市", "防城港市", "钦州市", "贵港市", "玉林市", "百色市", "贺州市", "河池市", "来宾市", "崇左市",

            // 海南省
            "海口市", "三亚市", "三沙市", "儋州市", "五指山市", "琼海市", "文昌市", "万宁市", "东方市", "定安县", "屯昌县", "澄迈县", "临高县", "白沙黎族自治县", "昌江黎族自治县", "乐东黎族自治县", "陵水黎族自治县", "保亭黎族苗族自治县", "琼中黎族苗族自治县",

            // 四川省
            "成都市", "自贡市", "攀枝花市", "泸州市", "德阳市", "绵阳市", "广元市", "遂宁市", "内江市", "乐山市", "南充市", "眉山市", "宜宾市", "广安市", "达州市", "雅安市", "巴中市", "资阳市", "阿坝藏族羌族自治州", "甘孜藏族自治州", "凉山彝族自治州",

            // 贵州省
            "贵阳市", "六盘水市", "遵义市", "安顺市", "毕节市", "铜仁市", "黔西南布依族苗族自治州", "黔东南苗族侗族自治州", "黔南布依族苗族自治州",

            // 云南省
            "昆明市", "曲靖市", "玉溪市", "保山市", "昭通市", "丽江市", "普洱市", "临沧市", "楚雄彝族自治州", "红河哈尼族彝族自治州", "文山壮族苗族自治州", "西双版纳傣族自治州", "大理白族自治州", "德宏傣族景颇族自治州", "怒江傈僳族自治州", "迪庆藏族自治州",

            // 陕西省
            "西安市", "铜川市", "宝鸡市", "咸阳市", "渭南市", "延安市", "汉中市", "榆林市", "安康市", "商洛市",

            // 宁夏回族自治区
            "银川市", "石嘴山市", "吴忠市", "固原市", "中卫市"
    };

    // 渠道来源
    private static final String[] SOURCES = {"闪信", "速贝", "哈啰", "360", "全民", "人品", "拍拍"};

    // 学历（按分布比例）
    private static final String[] EDUCATIONS = {
            "大专", "大专", "大专", // 30%
            "中专职高技校", "中专职高技校", // 15%
            "高中", "高中", // 20%
            "本科", "本科", // 20%
            "小学", "初中", "硕士", "其他" // 15%
    };

    // 职业（按分布比例）
    private static final String[] OCCUPATIONS = {
            "商业、服务业人员", "商业、服务业人员", "商业、服务业人员", "商业、服务业人员", "商业、服务业人员", // 50%
            "国家机关、党群组织、企业、事业单位负责人", "专业技术人员", "办事人员和有关人员", "农、林、牧、渔水利业生产人员", "生产、运输设备操作人员及有关人员", "不便分类的其他从业人员", // 30%
            "其他", "其他" // 20%
    };

    // 婚姻状况（按分布比例）
    private static final String[] MARITAL_STATUS = {
            "已婚", "已婚", "已婚", "已婚", "已婚", "已婚", "已婚", "已婚", "已婚", "已婚", "已婚", "已婚", "已婚", // 65%
            "未婚", "未婚", "未婚", "未婚", "未婚", // 25%
            "其他", "其他", // 7%
            "离异" // 3%
    };

    // 贷款期限
    private static final int[] LOAN_TERMS = {3, 6, 12};

    // 还款方式
    private static final String[] REPAY_TYPES = {"等额本息", "等额本金"};

    // 贷款用途（按分布比例）
    private static final String[] LOAN_PURPOSES = {
            "消费", "消费", "消费", "消费", "消费", "消费", // 60%
            "其他", "装修", "医疗", "教育", "旅游" // 40%
    };

    // 贷款用途
    private static final String[] LOAN_USES = {"消费", "装修", "教育", "医疗", "旅游", "其他"};

    // 产品名称和分布权重（按放款金额）
    private static final Map<String, Double> PRODUCT_DISTRIBUTION = Map.of(
            "浩瀚小贷", 0.30,  // 30%
            "盈峰小贷", 0.30,  // 30%
            "新网银行", 0.20,  // 20%
            "江山小贷", 0.20   // 20%
    );

    // 迁徙率配置（M2催回率降到20%-30%）
    private static final Map<String, Double> MIGRATION_RATES = Map.of(
            "M1_M2", 0.25,   // M1到M2迁徙率25%（M2催回率75%）
            "M2_M3", 0.20,   // M2到M3迁徙率20%（M2催回率80%）
            "M3_M4", 0.15,   // M3到M4迁徙率15%
            "M4_M5", 0.10,   // M4到M5迁徙率10%
            "M5_M6", 0.08    // M5到M6迁徙率8%
    );

    private static final String[] PRODUCT_NAMES = {"新网银行", "盈峰小贷", "江山小贷", "浩瀚小贷"};
    private static final String[] PRODUCT_M = {
            "M1","M1","M1","M1","M1","M1","M1","M1","M1","M1","M1","M1","M1","M1","M1","M1","M1","M1","M1","M1","M1","M1","M1","M1",//96%
            "M2","M2","M2",//3%
            "M3",//1%
            "M4","M5","M6"//0% (共3个，每个约0%)
    };

    // 身份证前缀映射（全国除西藏、新疆、甘肃、青海）
    private static final Map<String, String> CITY_ID_PREFIX = new HashMap<>();

    private static final Map<String, String> CITY_CODE_MAP = new HashMap<>();

    static {
        // 直辖市
        CITY_CODE_MAP.put("北京市", "110000");
        CITY_CODE_MAP.put("上海市", "310000");
        CITY_CODE_MAP.put("天津市", "120000");
        CITY_CODE_MAP.put("重庆市", "500000");

        // 河北省
        CITY_CODE_MAP.put("石家庄市", "130100");
        CITY_CODE_MAP.put("唐山市", "130200");
        CITY_CODE_MAP.put("秦皇岛市", "130300");
        CITY_CODE_MAP.put("邯郸市", "130400");
        CITY_CODE_MAP.put("邢台市", "130500");
        CITY_CODE_MAP.put("保定市", "130600");
        CITY_CODE_MAP.put("张家口市", "130700");
        CITY_CODE_MAP.put("承德市", "130800");
        CITY_CODE_MAP.put("沧州市", "130900");
        CITY_CODE_MAP.put("廊坊市", "131000");
        CITY_CODE_MAP.put("衡水市", "131100");

        // 山西省
        CITY_CODE_MAP.put("太原市", "140100");
        CITY_CODE_MAP.put("大同市", "140200");
        CITY_CODE_MAP.put("阳泉市", "140300");
        CITY_CODE_MAP.put("长治市", "140400");
        CITY_CODE_MAP.put("晋城市", "140500");
        CITY_CODE_MAP.put("朔州市", "140600");
        CITY_CODE_MAP.put("晋中市", "140700");
        CITY_CODE_MAP.put("运城市", "140800");
        CITY_CODE_MAP.put("忻州市", "140900");
        CITY_CODE_MAP.put("临汾市", "141000");
        CITY_CODE_MAP.put("吕梁市", "141100");

        // 辽宁省
        CITY_CODE_MAP.put("沈阳市", "210100");
        CITY_CODE_MAP.put("大连市", "210200");
        CITY_CODE_MAP.put("鞍山市", "210300");
        CITY_CODE_MAP.put("抚顺市", "210400");
        CITY_CODE_MAP.put("本溪市", "210500");
        CITY_CODE_MAP.put("丹东市", "210600");
        CITY_CODE_MAP.put("锦州市", "210700");
        CITY_CODE_MAP.put("营口市", "210800");
        CITY_CODE_MAP.put("阜新市", "210900");
        CITY_CODE_MAP.put("辽阳市", "211000");
        CITY_CODE_MAP.put("盘锦市", "211100");
        CITY_CODE_MAP.put("铁岭市", "211200");
        CITY_CODE_MAP.put("朝阳市", "211300");
        CITY_CODE_MAP.put("葫芦岛市", "211400");

        // 江苏省
        CITY_CODE_MAP.put("南京市", "320100");
        CITY_CODE_MAP.put("无锡市", "320200");
        CITY_CODE_MAP.put("徐州市", "320300");
        CITY_CODE_MAP.put("常州市", "320400");
        CITY_CODE_MAP.put("苏州市", "320500");
        CITY_CODE_MAP.put("南通市", "320600");
        CITY_CODE_MAP.put("连云港市", "320700");
        CITY_CODE_MAP.put("淮安市", "320800");
        CITY_CODE_MAP.put("盐城市", "320900");
        CITY_CODE_MAP.put("扬州市", "321000");
        CITY_CODE_MAP.put("镇江市", "321100");
        CITY_CODE_MAP.put("泰州市", "321200");
        CITY_CODE_MAP.put("宿迁市", "321300");

        // 浙江省
        CITY_CODE_MAP.put("杭州市", "330100");
        CITY_CODE_MAP.put("宁波市", "330200");
        CITY_CODE_MAP.put("温州市", "330300");
        CITY_CODE_MAP.put("嘉兴市", "330400");
        CITY_CODE_MAP.put("湖州市", "330500");
        CITY_CODE_MAP.put("绍兴市", "330600");
        CITY_CODE_MAP.put("金华市", "330700");
        CITY_CODE_MAP.put("衢州市", "330800");
        CITY_CODE_MAP.put("舟山市", "330900");
        CITY_CODE_MAP.put("台州市", "331000");
        CITY_CODE_MAP.put("丽水市", "331100");

        // 安徽省
        CITY_CODE_MAP.put("合肥市", "340100");
        CITY_CODE_MAP.put("芜湖市", "340200");
        CITY_CODE_MAP.put("蚌埠市", "340300");
        CITY_CODE_MAP.put("淮南市", "340400");
        CITY_CODE_MAP.put("马鞍山市", "340500");
        CITY_CODE_MAP.put("淮北市", "340600");
        CITY_CODE_MAP.put("铜陵市", "340700");
        CITY_CODE_MAP.put("安庆市", "340800");
        CITY_CODE_MAP.put("黄山市", "341000");
        CITY_CODE_MAP.put("滁州市", "341100");
        CITY_CODE_MAP.put("阜阳市", "341200");
        CITY_CODE_MAP.put("宿州市", "341300");
        CITY_CODE_MAP.put("六安市", "341500");
        CITY_CODE_MAP.put("亳州市", "341600");
        CITY_CODE_MAP.put("池州市", "341700");
        CITY_CODE_MAP.put("宣城市", "341800");

        // 福建省
        CITY_CODE_MAP.put("福州市", "350100");
        CITY_CODE_MAP.put("厦门市", "350200");
        CITY_CODE_MAP.put("莆田市", "350300");
        CITY_CODE_MAP.put("三明市", "350400");
        CITY_CODE_MAP.put("泉州市", "350500");
        CITY_CODE_MAP.put("漳州市", "350600");
        CITY_CODE_MAP.put("南平市", "350700");
        CITY_CODE_MAP.put("龙岩市", "350800");
        CITY_CODE_MAP.put("宁德市", "350900");

        // 江西省
        CITY_CODE_MAP.put("南昌市", "360100");
        CITY_CODE_MAP.put("景德镇市", "360200");
        CITY_CODE_MAP.put("萍乡市", "360300");
        CITY_CODE_MAP.put("九江市", "360400");
        CITY_CODE_MAP.put("新余市", "360500");
        CITY_CODE_MAP.put("鹰潭市", "360600");
        CITY_CODE_MAP.put("赣州市", "360700");
        CITY_CODE_MAP.put("吉安市", "360800");
        CITY_CODE_MAP.put("宜春市", "360900");
        CITY_CODE_MAP.put("抚州市", "361000");
        CITY_CODE_MAP.put("上饶市", "361100");

        // 山东省
        CITY_CODE_MAP.put("济南市", "370100");
        CITY_CODE_MAP.put("青岛市", "370200");
        CITY_CODE_MAP.put("淄博市", "370300");
        CITY_CODE_MAP.put("枣庄市", "370400");
        CITY_CODE_MAP.put("东营市", "370500");
        CITY_CODE_MAP.put("烟台市", "370600");
        CITY_CODE_MAP.put("潍坊市", "370700");
        CITY_CODE_MAP.put("济宁市", "370800");
        CITY_CODE_MAP.put("泰安市", "370900");
        CITY_CODE_MAP.put("威海市", "371000");
        CITY_CODE_MAP.put("日照市", "371100");
        CITY_CODE_MAP.put("临沂市", "371300");
        CITY_CODE_MAP.put("德州市", "371400");
        CITY_CODE_MAP.put("聊城市", "371500");
        CITY_CODE_MAP.put("滨州市", "371600");
        CITY_CODE_MAP.put("菏泽市", "371700");
    }

    private static final Random random = new Random();

    // 每月放款递增配置
    private static final BigDecimal MONTHLY_INCREASE_RATE = new BigDecimal("0.1"); // 每月递增10%

    /**
     * 生成指定月份的数据
     */
    public static List<CustomerOrder> generateMonthlyData(LocalDate month, int targetOrderCount) {
        List<CustomerOrder> orders = new ArrayList<>();
        List<CustomerInfo> customers = new ArrayList<>();
        List<CustomerRepayPlan> repayPlans = new ArrayList<>();

        // 计算该月份的放款金额（递增）
        long daysFromStart = month.toEpochDay() - START_DATE.toEpochDay();

        // 确定产品分布
        Map<String, Integer> productDistribution = calculateProductDistribution(month, targetOrderCount);

        for (Map.Entry<String, Integer> entry : productDistribution.entrySet()) {
            String productName = entry.getKey();
            int orderCount = entry.getValue();

            for (int i = 0; i < orderCount; i++) {
                // 生成客户信息
                CustomerInfo customer = generateCustomerInfo(month);
                customers.add(customer);

                // 生成订单
                CustomerOrder order = generateCustomerOrder(customer, month, productName);
                orders.add(order);

                // 生成还款计划
                List<CustomerRepayPlan> plans = generateRepayPlan(order);
                repayPlans.addAll(plans);
            }
        }

        return orders;
    }

    /**
     * 计算产品分布
     */
    private static Map<String, Integer> calculateProductDistribution(LocalDate month, int totalOrders) {
        Map<String, Integer> distribution = new HashMap<>();

        // 判断是否在前6个月（只有浩瀚小贷）
        if (month.isBefore(START_DATE.plusMonths(HAOHAN_ONLY_MONTHS))) {
            distribution.put("浩瀚小贷", totalOrders);
        } else {
            // 按权重分配
            int haohanCount = (int) (totalOrders * PRODUCT_DISTRIBUTION.get("浩瀚小贷"));
            int yingfengCount = (int) (totalOrders * PRODUCT_DISTRIBUTION.get("盈峰小贷"));
            int xinwangCount = (int) (totalOrders * PRODUCT_DISTRIBUTION.get("新网银行"));
            int jiangshanCount = totalOrders - haohanCount - yingfengCount - xinwangCount;

            distribution.put("浩瀚小贷", haohanCount);
            distribution.put("盈峰小贷", yingfengCount);
            distribution.put("新网银行", xinwangCount);
            distribution.put("江山小贷", jiangshanCount);
        }

        return distribution;
    }

    /**
     * 生成用户信息
     */
    public static CustomerInfo generateCustomerInfo(LocalDate orderDate) {
        CustomerInfo customer = new CustomerInfo();
        customer.setId(customerIdCounter.incrementAndGet());
        // 使用示例
        Map.Entry<String, String> randomEntry = getRandomCityCode();
        String city="";
        String code="";
        if (randomEntry != null) {
            city = randomEntry.getKey();
            code = randomEntry.getValue();
        }
        // 随机选择城市
        customer.setSaleCityName(city);

        // 生成脱敏姓名
        customer.setPlName(generateMaskedName());

        // 生成脱敏手机号
        customer.setPlPhone(generateMaskedPhone());

        // 性别（男75%，女25%）
        customer.setGender(random.nextDouble() < 0.75 ? "男" : "女");

        // 生成脱敏身份证号（根据性别生成倒数第二位）
        customer.setPlIdNo(generateMaskedIdNo(code, customer.getGender()));

        // 年龄（正态分布，没有18以下的）
        customer.setAge(generateNormalDistributedAge());

        // 学历
        customer.setEducation(EDUCATIONS[random.nextInt(EDUCATIONS.length)]);

        // 职业（按分布比例）
        customer.setOccupation(OCCUPATIONS[random.nextInt(OCCUPATIONS.length)]);

        // 婚姻状况
        customer.setMaritalStatus(MARITAL_STATUS[random.nextInt(MARITAL_STATUS.length)]);

        // 渠道来源
        customer.setSource(SOURCES[random.nextInt(SOURCES.length)]);

        // 登录状态
        customer.setLoginStatus("通过");

        // 创建时间（与订单生成时间一致，时分秒在06:00:00到23:00:00之间随机）
        int hour = 6 + random.nextInt(18); // 6-23点
        int minute = random.nextInt(60);   // 0-59分
        int second = random.nextInt(60);   // 0-59秒
        String timeStr = String.format("%02d:%02d:%02d", hour, minute, second);
        customer.setCreatedTime(orderDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " " + timeStr);

        return customer;
    }

    /**
     * 生成客户订单
     */
    public static CustomerOrder generateCustomerOrder(CustomerInfo customerInfo, LocalDate loanDate, String productName) {
        CustomerOrder order = new CustomerOrder();

        // 订单号
        order.setOrderNo("ORD"+customerInfo.getId());
        order.setCustomerId(customerInfo.getId());

        // 用户信息
        order.setPlName(customerInfo.getPlName());
        order.setPlPhone(customerInfo.getPlPhone());
        order.setPlIdNo(customerInfo.getPlIdNo());
        order.setSaleCityName(customerInfo.getSaleCityName());

        // 放款时间
        order.setFrTime(loanDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));

        // 贷款期限
        int term = LOAN_TERMS[random.nextInt(LOAN_TERMS.length)];
        order.setLoanTerm(term + "月");

        // 对客利率（18%或24%）
        String rate = random.nextBoolean() ? "18%" : "24%";
        order.setProductRate(rate);

        // 贷款金额（平均5000左右，精确到百位）
        BigDecimal loanAmount = BigDecimal.valueOf((3000 + random.nextInt(4000)) / 100 * 100)
                .setScale(2, RoundingMode.HALF_UP);
        order.setLoanAmount(loanAmount);

        // 产品名称（直接使用传入的参数）
        order.setProductName(productName);

        // 还款方式
        String repayType = REPAY_TYPES[random.nextInt(REPAY_TYPES.length)];
        // 如果还款方式是先息后本，则贷款期限必须是1
//        if ("先息后本".equals(repayType)) {
//            order.setLoanTerm("1月");
//            term = 1;
//        }
        order.setRepayType(repayType);

        // 贷款用途（按分布比例）
        order.setLoanUse(LOAN_PURPOSES[random.nextInt(LOAN_PURPOSES.length)]);
        LocalDate now=LocalDate.of(2025, 9, 30);

        // 状态和结清日期（2%提前还款，均匀分布在不同放款时间）
        boolean isEarlyRepay = false;
        // 使用订单号确保提前结清订单在不同放款时间均匀分布
        if (term == 3) {
            // 3期贷款：使用订单号确保均匀分布
            long orderHash = Math.abs(order.getOrderNo().hashCode());
            double earlyRepayRandom = (orderHash % 10000) / 10000.0;
            isEarlyRepay = earlyRepayRandom < 0.016; // 1.6%提前结清
        } else if (term == 6) {
            // 6期贷款：使用订单号确保均匀分布
            long orderHash = Math.abs(order.getOrderNo().hashCode());
            double earlyRepayRandom = (orderHash % 10000) / 10000.0;
            isEarlyRepay = earlyRepayRandom < 0.016; // 1.6%提前结清
        } else if (term == 12) {
            // 12期贷款：使用订单号确保均匀分布
            long orderHash = Math.abs(order.getOrderNo().hashCode());
            double earlyRepayRandom = (orderHash % 10000) / 10000.0;
            isEarlyRepay = earlyRepayRandom < 0.017; // 1.7%提前结清
        }
        
            // 结清日期在还款周期一半前后
            int halfTerm = term / 2;
            int settleMonth = halfTerm + random.nextInt(halfTerm + 1);
        LocalDate setSettleDate=loanDate.plusMonths(settleMonth);
        if(setSettleDate.isBefore(now)&&isEarlyRepay){
            order.setStatus("已结清");
            order.setSettleDate(setSettleDate);
            order.setRemainPayAmount(BigDecimal.ZERO);
        } else {
            // 根据当前时间判断状态
//            LocalDate now = LocalDate.now();
//            LocalDate now=LocalDate.of(2025, 9, 30);
            if (loanDate.plusMonths(term).isBefore(now)) {
                order.setStatus("已结清");
                order.setSettleDate(loanDate.plusMonths(term));
                order.setRemainPayAmount(BigDecimal.ZERO);
            } else {
                order.setStatus("未结清");
                order.setSettleDate(null);
                // 计算剩余金额（简化计算）
                long remainingMonths = loanDate.plusMonths(term).toEpochDay() - now.toEpochDay();
                remainingMonths = Math.max(0, remainingMonths / 30);
                order.setRemainPayAmount(loanAmount.multiply(BigDecimal.valueOf(remainingMonths))
                        .divide(BigDecimal.valueOf(term), 2, RoundingMode.HALF_UP));
            }
        }

        return order;
    }

    /**
     * 生成客户还款计划
     */
    public static List<CustomerRepayPlan> generateRepayPlan(CustomerOrder order) {
        List<CustomerRepayPlan> plans = new ArrayList<>();

        String loanTerm = order.getLoanTerm();
        int term = Integer.parseInt(loanTerm.replace("月", ""));
        BigDecimal loanAmount = order.getLoanAmount();
        String rateStr = order.getProductRate();
        double rate = Double.parseDouble(rateStr.replace("%", "")) / 100.0;
        String repayType = order.getRepayType();

        LocalDate loanDate = LocalDate.parse(order.getFrTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
//        LocalDate now = LocalDate.now();
        LocalDate now=LocalDate.of(2025, 9, 30);

        for (int i = 1; i <= term; i++) {
            CustomerRepayPlan plan = new CustomerRepayPlan();

            plan.setOrderNo(order.getOrderNo());
            plan.setBillId(order.getOrderNo() + "_" + String.format("%03d", i));
            plan.setLoanAmount(loanAmount);
            plan.setLoanTerm(loanTerm);
            plan.setBillTenor((long) i);
            plan.setRate(BigDecimal.valueOf(rate));
            plan.setMonthRate(BigDecimal.valueOf(rate / 12));

            // 应还款日期
            LocalDate dueDate = loanDate.plusMonths(i);
            plan.setDueDate(dueDate);

            // 计算本期应还金额
            calculateRepayAmount(plan, loanAmount, rate, term, repayType, i);

            // 初始状态设置
            plan.setRepayStatus("未到期");
            plan.setActualRepayDate(null);
            plan.setActualRepayMoney(BigDecimal.ZERO);
            plan.setOverdueDays(0);
            plan.setPenaltyInterest(BigDecimal.ZERO);

            plans.add(plan);
        }

        // 应用Vintage和迁徙率逻辑
        applyVintageMigrationLogic(plans, order, now);

        // 更新订单状态和剩余金额
        updateOrderStatusAndRemainAmount(order, plans, now);

        return plans;
    }

    /**
     * 计算本期应还金额
     */
    private static void calculateRepayAmount(CustomerRepayPlan plan, BigDecimal loanAmount,
                                             double rate, int term, String repayType, int currentTerm) {
        BigDecimal monthlyRate = BigDecimal.valueOf(rate / 12);

        switch (repayType) {
            case "等额本息":
                // 等额本息计算
                BigDecimal monthlyPayment = loanAmount.multiply(monthlyRate)
                        .multiply(BigDecimal.ONE.add(monthlyRate).pow(term))
                        .divide(BigDecimal.ONE.add(monthlyRate).pow(term).subtract(BigDecimal.ONE), 2, RoundingMode.HALF_UP);

                BigDecimal remainingPrincipal = loanAmount;
                for (int i = 1; i < currentTerm; i++) {
                    BigDecimal interest = remainingPrincipal.multiply(monthlyRate);
                    BigDecimal principal = monthlyPayment.subtract(interest);
                    remainingPrincipal = remainingPrincipal.subtract(principal);
                }

                BigDecimal currentInterest = remainingPrincipal.multiply(monthlyRate);
                BigDecimal currentPrincipal = monthlyPayment.subtract(currentInterest);

                plan.setNowPayPrincipal(currentPrincipal);
                plan.setNowPayInterest(currentInterest);
                plan.setNowPayAmount(monthlyPayment);
                break;

            case "等额本金":
                // 等额本金计算
                BigDecimal monthlyPrincipal = loanAmount.divide(BigDecimal.valueOf(term), 2, RoundingMode.HALF_UP);
                BigDecimal remainingPrincipal2 = loanAmount.subtract(monthlyPrincipal.multiply(BigDecimal.valueOf(currentTerm - 1)));
                BigDecimal currentInterest2 = remainingPrincipal2.multiply(monthlyRate);

                plan.setNowPayPrincipal(monthlyPrincipal);
                plan.setNowPayInterest(currentInterest2);
                plan.setNowPayAmount(monthlyPrincipal.add(currentInterest2));
                break;

//            case "先息后本":
//                // 先息后本计算
//                if (currentTerm == term) {
//                    plan.setNowPayPrincipal(loanAmount);
//                    plan.setNowPayInterest(BigDecimal.ZERO);
//                    plan.setNowPayAmount(loanAmount);
//                } else {
//                    BigDecimal interest = loanAmount.multiply(monthlyRate);
//                    plan.setNowPayPrincipal(BigDecimal.ZERO);
//                    plan.setNowPayInterest(interest);
//                    plan.setNowPayAmount(interest);
//                }
//                break;
        }
    }


    /**
     * 计算每月还款金额
     * 公式：每月偿还本息=〔贷款本金×月利率×(1＋月利率)＾还款月数〕÷〔(1＋月利率)＾还款月数-1〕
     * @param loanAmount    贷款金额
     * @param annualRate    年利率
     * @param totalMonths   还款总月数
     * @return 每月还款金额
     */
    public static BigDecimal calculateMonthlyPayment(BigDecimal loanAmount, BigDecimal annualRate, int totalMonths) {
        BigDecimal monthlyRate = annualRate.divide(BigDecimal.valueOf(12), 10, RoundingMode.HALF_UP);
        //本金x月利率X(1+月利率)^n
        BigDecimal numerator = loanAmount.multiply(monthlyRate).multiply((BigDecimal.ONE.add(monthlyRate)).pow(totalMonths));
        //(1+月利率)^n -1
        BigDecimal denominator = (BigDecimal.ONE.add(monthlyRate))
                .pow(totalMonths)
                .subtract(BigDecimal.ONE);
        return numerator.divide(denominator, 4, RoundingMode.HALF_UP);
    }

    /**
     * 生成脱敏姓名
     */
    private static String generateMaskedName() {
        String[] surnames = {
                "王", "李", "张", "刘", "陈", "杨", "赵", "黄", "周", "吴", "徐", "孙", "胡", "朱", "高", "林", "何", "郭", "马", "罗",
                "梁", "宋", "郑", "谢", "韩", "唐", "冯", "于", "董", "萧", "程", "曹", "袁", "邓", "许", "傅", "沈", "曾", "彭", "吕",
                "苏", "卢", "蒋", "蔡", "贾", "丁", "魏", "薛", "叶", "余", "潘", "杜", "戴", "夏", "钟", "汪", "田", "任", "姜",
                "范", "方", "石", "姚", "谭", "廖", "邹", "熊", "金", "陆", "郝", "孔", "白", "崔", "康", "毛", "邱", "秦", "江", "史",
                "顾", "侯", "邵", "孟", "龙", "万", "段", "钱", "汤", "尹", "黎", "易", "常", "武", "乔", "贺", "赖", "龚", "文",
                "庞", "樊", "兰", "殷", "施", "陶", "洪", "翟", "安", "颜", "倪", "严", "牛", "温", "芦", "季", "俞", "章", "鲁", "葛",
                "伍", "韦", "申", "尤", "毕", "聂", "丛", "焦", "向", "柳", "邢", "路", "岳", "齐", "沿", "梅", "莫", "庄", "辛", "管",
                "祝", "左", "涂", "谷", "祁", "时", "舒", "耿", "牟", "卜", "路", "詹", "关", "苗", "凌", "费", "纪", "靳", "盛", "童",
                "欧", "项", "曲", "成", "游", "阳", "裴", "席", "卫", "查", "屈", "鲍", "位", "覃", "霍", "翁", "隋", "植", "甘",
                "景", "单", "包", "司", "柏", "宁", "柯", "阮", "桂", "闵",  "梁", "宋", "郑",
                "谢", "韩", "唐", "冯", "于", "董", "萧", "程", "曹", "袁", "邓", "许", "傅", "沈", "曾", "彭", "吕", "苏", "卢", "蒋",
                "蔡", "贾", "丁", "魏", "薛", "叶", "阎", "余", "潘", "杜", "戴", "夏", "钟", "汪", "田", "任", "姜", "范", "方", "石",
                "姚", "谭", "廖", "邹", "熊", "金", "陆", "郝", "孔", "白", "崔", "康", "毛", "邱", "秦", "江", "史", "顾", "侯", "邵",
                "孟", "龙", "万", "段", "钱", "汤", "尹", "黎", "易", "常", "武", "乔", "贺", "赖", "龚", "文", "庞", "樊", "兰",
                "殷", "施", "陶", "洪", "翟", "安", "颜", "倪", "严", "牛", "温", "芦", "季", "俞", "章", "鲁", "葛", "伍", "韦", "申",
                "尤", "毕", "聂", "丛", "焦", "向", "邢", "路", "岳", "齐", "莫", "庄", "辛", "管", "祝", "左", "涂",
                "谷", "祁", "时", "舒", "耿", "牟", "卜", "路", "詹", "关", "苗", "凌", "费", "纪", "靳", "盛", "童", "欧", "项",
                "席", "卫", "查", "屈", "鲍", "位", "覃", "霍", "翁", "隋", "植", "甘", "景", "薄", "单", "宁", "柯", "阮"
        };

        String surname = surnames[random.nextInt(surnames.length)];

        // 脱敏格式：徐** 或 欧阳**
        return surname + "**";
    }

    /**
     * 应用Vintage和迁徙率逻辑到还款计划
     */
    private static void applyVintageMigrationLogic(List<CustomerRepayPlan> plans, CustomerOrder order, LocalDate now) {
        if (plans.isEmpty()) return;

        // 如果订单状态是已结清，则所有还款计划都标记为已结清
        if ("已结清".equals(order.getStatus())) {
            LocalDate settleDate = order.getSettleDate();
            if (settleDate != null) {
                for (CustomerRepayPlan plan : plans) {
                    LocalDate dueDate = plan.getDueDate();
                    
                    // 根据dueDate与settleDate的关系处理不同的情况
                    LocalDate maxRepayDate = LocalDate.of(2025, 9, 30);
                    
                    if (dueDate.isBefore(settleDate)) {
                        // dueDate < settleDate：正常还款，实际还款金额等于应还金额
                        LocalDate actualRepayDate = dueDate.isAfter(maxRepayDate) ? maxRepayDate : dueDate;
                        plan.setRepayStatus("已结清");
                        plan.setActualRepayDate(actualRepayDate);
                        plan.setActualRepayMoney(plan.getNowPayAmount());
                        plan.setActualPrincipal(plan.getNowPayPrincipal());
                        plan.setActualInterest(plan.getNowPayInterest());
                        plan.setOverdueDays(0);
                        plan.setPenaltyInterest(BigDecimal.ZERO);
                    } else if (dueDate.isEqual(settleDate)) {
                        // dueDate == settleDate：提前结清，实际还款本金等于剩余期数应还本金之和
                        LocalDate actualRepayDate = settleDate.isAfter(maxRepayDate) ? maxRepayDate : settleDate;
                        plan.setRepayStatus("已结清");
                        plan.setActualRepayDate(actualRepayDate);
                        
                        // 计算剩余期数应还本金之和
                        BigDecimal totalRemainingPrincipal = BigDecimal.ZERO;
                        int currentTerm = plan.getBillTenor().intValue();
                        int totalTerms = Integer.parseInt(order.getLoanTerm().replace("月", ""));
                        
                        // 计算从当前期到最后一期的所有应还本金
                        for (int i = currentTerm; i <= totalTerms; i++) {
                            final int termIndex = i;
                            CustomerRepayPlan remainingPlan = plans.stream()
                                    .filter(p -> p.getBillTenor().intValue() == termIndex)
                                    .findFirst()
                                    .orElse(null);
                            
                            if (remainingPlan != null) {
                                totalRemainingPrincipal = totalRemainingPrincipal.add(remainingPlan.getNowPayPrincipal());
                            }
                        }
                        
                        // 实际还款本金 = 剩余期数应还本金之和
                        plan.setActualPrincipal(totalRemainingPrincipal);
                        // 实际还款利息 = 本期的应还利息
                        plan.setActualInterest(plan.getNowPayInterest());
                        // 实际还款金额 = 实际还款本金 + 实际还款利息
                        plan.setActualRepayMoney(totalRemainingPrincipal.add(plan.getNowPayInterest()));
                        plan.setOverdueDays(0);
                        plan.setPenaltyInterest(BigDecimal.ZERO);
                        
                        // 将剩余期数的还款计划也标记为已结清，实还金额为0
                        for (int i = currentTerm + 1; i <= totalTerms; i++) {
                            final int termIndex = i;
                            CustomerRepayPlan remainingPlan = plans.stream()
                                    .filter(p -> p.getBillTenor().intValue() == termIndex)
                                    .findFirst()
                                    .orElse(null);
                            
                            if (remainingPlan != null) {
                                remainingPlan.setRepayStatus("已结清");
                                remainingPlan.setActualRepayDate(actualRepayDate);
                                remainingPlan.setActualRepayMoney(BigDecimal.ZERO);
                                remainingPlan.setActualPrincipal(BigDecimal.ZERO);
                                remainingPlan.setActualInterest(BigDecimal.ZERO);
                                remainingPlan.setOverdueDays(0);
                                remainingPlan.setPenaltyInterest(BigDecimal.ZERO);
                            }
                        }
                    } else {
                        // dueDate > settleDate的期数也标记为已结清，但实还金额为0
                        LocalDate actualRepayDate = settleDate.isAfter(maxRepayDate) ? maxRepayDate : settleDate;
                        plan.setRepayStatus("已结清");
                        plan.setActualRepayDate(actualRepayDate);
                        plan.setActualRepayMoney(BigDecimal.ZERO);
                        plan.setActualPrincipal(BigDecimal.ZERO);
                        plan.setActualInterest(BigDecimal.ZERO);
                        plan.setOverdueDays(0);
                        plan.setPenaltyInterest(BigDecimal.ZERO);
                    }
                }
            }
            return; // 订单已结清，直接返回
        }

        // 设置处理截止日期
        LocalDate processingCutoffDate = LocalDate.of(2025, 9, 30);
        LocalDate maxRepayDate = LocalDate.of(2025, 9, 30);
        
        // 重新设计逾期逻辑：确保每个月都有逾期和逾期已还记录，总逾期比例5%
        boolean hasFirstOverdue = false; // 标记是否已经出现第一次逾期
        boolean hasCurrentOverdue = false; // 标记当前期数是否逾期

        // 为每个还款计划应用逾期逻辑
        for (CustomerRepayPlan plan : plans) {
            LocalDate dueDate = plan.getDueDate();

            // 2025-10-01及以后的数据都标记为未到期
            if (dueDate.isAfter(processingCutoffDate) || dueDate.isEqual(processingCutoffDate)) {
                plan.setRepayStatus("未到期");
                plan.setActualRepayDate(null);
                plan.setActualRepayMoney(BigDecimal.ZERO);
                plan.setOverdueDays(0);
                continue;
            }

            // 处理2025-09-30之前的数据
            if (dueDate.isBefore(processingCutoffDate)) {
                // 已到期的计划
                if (hasFirstOverdue) {
                    // 第一次逾期之后的期数：有可能继续逾期，也有可能已结清
                    // 但是状态是逾期的期数后面的期数不能存在已结清状态的数据
                    int period = plan.getBillTenor().intValue();
                    String overdueBucket = selectOverdueBucketWithDetailedDistribution(order.getOrderNo(), period);
                    
                    // 如果前面有逾期状态，则当前期数不能是已结清
                    if (hasCurrentOverdue) {
                        // 继续逾期
                        long overdueDays = now.toEpochDay() - dueDate.toEpochDay();
                    plan.setRepayStatus("逾期");
                    plan.setActualRepayDate(null);
                    plan.setActualRepayMoney(BigDecimal.ZERO);
                    plan.setOverdueDays((int) overdueDays);

                    // 计算罚息
                    if (overdueDays > 3) {
                        BigDecimal penaltyRate = plan.getRate().divide(new BigDecimal("365"), 10, RoundingMode.HALF_UP)
                                    .multiply(new BigDecimal("1.5"));
                        BigDecimal penaltyInterest = plan.getNowPayAmount()
                                .multiply(penaltyRate)
                                .multiply(BigDecimal.valueOf(overdueDays))
                                .setScale(2, RoundingMode.HALF_UP);
                        plan.setPenaltyInterest(penaltyInterest);
                    } else {
                        plan.setPenaltyInterest(BigDecimal.ZERO);
                    }
                    plan.setNowPayAmount(plan.getNowPayAmount().add(plan.getPenaltyInterest()));
                } else {
                        // 前面没有逾期状态，可以正常还款或逾期
                        if ("NORMAL".equals(overdueBucket)) {
                            // 正常还款，确保实际还款日期小于等于2025-09-30
                            LocalDate actualRepayDate = dueDate.isAfter(maxRepayDate) ? maxRepayDate : dueDate;
                            
                            plan.setRepayStatus("已结清");
                            plan.setActualRepayDate(actualRepayDate);
                            plan.setActualRepayMoney(plan.getNowPayAmount());
                            plan.setOverdueDays(0);
                            plan.setActualPrincipal(plan.getNowPayPrincipal());
                            plan.setActualInterest(plan.getNowPayInterest());
                            plan.setPenaltyInterest(BigDecimal.ZERO);
                        } else {
                            // 继续逾期
                            long overdueDays = now.toEpochDay() - dueDate.toEpochDay();
                            plan.setRepayStatus("逾期");
                            plan.setActualRepayDate(null);
                            plan.setActualRepayMoney(BigDecimal.ZERO);
                            plan.setOverdueDays((int) overdueDays);
                            hasCurrentOverdue = true; // 标记当前期数逾期

                            // 计算罚息
                            if (overdueDays > 3) {
                                BigDecimal penaltyRate = plan.getRate().divide(new BigDecimal("365"), 10, RoundingMode.HALF_UP)
                                        .multiply(new BigDecimal("1.5"));
                                BigDecimal penaltyInterest = plan.getNowPayAmount()
                                        .multiply(penaltyRate)
                                        .multiply(BigDecimal.valueOf(overdueDays))
                                        .setScale(2, RoundingMode.HALF_UP);
                                plan.setPenaltyInterest(penaltyInterest);
                    } else {
                                plan.setPenaltyInterest(BigDecimal.ZERO);
                            }
                            plan.setNowPayAmount(plan.getNowPayAmount().add(plan.getPenaltyInterest()));
                        }
                    }
                } else {
                    // 重新设计逾期逻辑：确保每个月都有逾期记录，总逾期比例5%
                    int period = plan.getBillTenor().intValue();
                    String overdueBucket = selectOverdueBucketWithDetailedDistribution(order.getOrderNo(), period);
                    
                        if ("NORMAL".equals(overdueBucket)) {
                        // 正常还款，确保实际还款日期小于等于2025-09-30
                        LocalDate actualRepayDate = dueDate.isAfter(maxRepayDate) ? maxRepayDate : dueDate;
                        
                            plan.setRepayStatus("已结清");
                            plan.setActualRepayDate(actualRepayDate);
                            plan.setActualRepayMoney(plan.getNowPayAmount());
                            plan.setOverdueDays(0);
                            plan.setActualPrincipal(plan.getNowPayPrincipal());
                            plan.setActualInterest(plan.getNowPayInterest());
                            plan.setPenaltyInterest(BigDecimal.ZERO);
                        } else {
                        // 逾期后还款
                            hasFirstOverdue = true;
                        hasCurrentOverdue = true; // 标记当前期数逾期
                        applyOverdueLogicWithDetailedDistribution(plan, order, dueDate, now, overdueBucket, plans);
                    }
                }
            } else {
                // 未到期的计划
                    plan.setRepayStatus("未到期");
                plan.setActualRepayDate(null);
                plan.setActualRepayMoney(BigDecimal.ZERO);
                plan.setOverdueDays(0);
            }
        }
    }

    /**
     * 生成正态分布的年龄
     */
    private static int generateNormalDistributedAge() {
        double rand = random.nextDouble();

        // 根据分布比例生成年龄
        if (rand < 0.01) { // 18-20（1%）
            return 18 + random.nextInt(3);
        } else if (rand < 0.06) { // 20-25（5%）
            return 20 + random.nextInt(6);
        } else if (rand < 0.16) { // 25-30（10%）
            return 25 + random.nextInt(6);
        } else if (rand < 0.51) { // 30-35（35%）
            return 30 + random.nextInt(6);
        } else if (rand < 0.76) { // 35-40（25%）
            return 35 + random.nextInt(6);
        } else if (rand < 0.91) { // 40-45（15%）
            return 40 + random.nextInt(6);
        } else if (rand < 0.97) { // 45-50（6%）
            return 45 + random.nextInt(6);
        } else if (rand < 1.00) { // 50-55（3%）
            return 50 + random.nextInt(6);
        } else { // 55以上（1%）
            return 55 + random.nextInt(10);
        }
    }

    /**
     * 生成该月内随机的一天
     */
    private static LocalDate generateRandomDayInMonth(LocalDate month) {
        // 获取该月的第一天和最后一天
        LocalDate firstDay = month.withDayOfMonth(1);
        LocalDate lastDay = month.withDayOfMonth(month.lengthOfMonth());

        // 计算该月的天数
        int daysInMonth = month.lengthOfMonth();

        // 生成随机天数（1到该月天数）
        int randomDay = 1 + random.nextInt(daysInMonth);

        return firstDay.withDayOfMonth(randomDay);
    }

    /**
     * 根据期数计算逾期率（基于真实业务数据的波状图模式，降低逾期率）
     * 在逾逾期比例按3月、6月、12月平均分配
     */
    private static double calculatePeriodOverdueRate(int period, String loanTerm) {
        // 第一期已经通过selectFirstPeriodOverdueBucket处理，这里只处理非第一期
        // 为了保持整体逾期率不变，需要调整非第一期的逾期率
        
        // 根据贷款期限调整逾期率，平均分配在逾逾期比例
        double baseRate;
        if ("3月".equals(loanTerm)) {
            // 3月贷款：平均分配在逾逾期比例
            baseRate = 0.00015; // 3月贷款的基础逾期率
        } else if ("6月".equals(loanTerm)) {
            // 6月贷款：平均分配在逾逾期比例
            baseRate = 0.00015; // 6月贷款的基础逾期率
        } else if ("12月".equals(loanTerm)) {
            // 12月贷款：平均分配在逾逾期比例
            baseRate = 0.00015; // 12月贷款的基础逾期率
        } else {
            // 其他期限保持原有逻辑
            baseRate = FIRST_PERIOD_OVERDUE_RATE * 0.5;
        }

        if (period == 1) {
            // 第一期不在这里处理，返回0
            return 0.0;
        } else if (period <= 2) {
            return baseRate * 1.5;
        } else if (period <= 10) {
            // 从第2期到第10期逐渐增加到峰值
            double progress = (period - 2.0) / 8.0; // 0到1的进度
            return baseRate * 1.5 + (baseRate * 10 - baseRate * 1.5) * progress;
        } else {
            // 从第10期开始逐渐下降
            double progress = Math.min((period - 10.0) / 14.0, 1.0); // 0到1的进度，最多到第24期
            return baseRate * 10 - (baseRate * 10 - baseRate * 1.5) * progress;
        }
    }

    /**
     * 选择逾期区间（按指定比例分布）
     */
    private static String selectOverdueBucket() {
        double bucketRandom = random.nextDouble();
        if (bucketRandom < 0.05) return "M1_7";     // 5% -> 逾期1-7天
        else if (bucketRandom < 0.08) return "M8_15"; // 3% -> 逾期8-15天
        else if (bucketRandom < 0.10) return "M16_30"; // 2% -> 逾期16-30天
        else if (bucketRandom < 0.115) return "M30_60"; // 1.5% -> 逾期30-60天
        else if (bucketRandom < 0.127) return "M60_90"; // 1.2% -> 逾期60-90天
        else if (bucketRandom < 0.137) return "M90_180"; // 1% -> 逾期90天以上
        else return "NORMAL"; // 正常还款（86.3%）
    }

    /**
     * 选择第一期逾期区间（按指定比例分布，保证整体逾期率不变）
     * 每个月都要有逾期未还的订单，并且比例差不多
     */
    private static String selectFirstPeriodOverdueBucket() {
        double bucketRandom = random.nextDouble();
        if (bucketRandom < 0.05) return "M1_7";     // 5% -> 逾期1-7天
        else if (bucketRandom < 0.08) return "M8_15"; // 3% -> 逾期8-15天
        else if (bucketRandom < 0.10) return "M16_30"; // 2% -> 逾期16-30天
        else if (bucketRandom < 0.115) return "M30_60"; // 1.5% -> 逾期30-60天
        else if (bucketRandom < 0.127) return "M60_90"; // 1.2% -> 逾期60-90天
        else if (bucketRandom < 0.137) return "M90_180"; // 1% -> 逾期90天以上
        else return "NORMAL"; // 正常还款（86.3%）
    }

    /**
     * 选择第一期逾期区间（确保每个月都有逾期未还的订单）
     * 使用基于订单号的哈希值来确保每个月都有逾期订单
     */
    private static String selectFirstPeriodOverdueBucketWithGuarantee(CustomerOrder order) {
        // 使用订单号生成一个稳定的随机数，确保每个月都有逾期订单
        long orderHash = Math.abs(order.getOrderNo().hashCode());
        double bucketRandom = (orderHash % 10000) / 10000.0; // 0-1之间的稳定值
        
        if (bucketRandom < 0.05) return "M1_7";     // 5% -> 逾期1-7天
        else if (bucketRandom < 0.08) return "M8_15"; // 3% -> 逾期8-15天
        else if (bucketRandom < 0.10) return "M16_30"; // 2% -> 逾期16-30天
        else if (bucketRandom < 0.115) return "M30_60"; // 1.5% -> 逾期30-60天
        else if (bucketRandom < 0.127) return "M60_90"; // 1.2% -> 逾期60-90天
        else if (bucketRandom < 0.137) return "M90_180"; // 1% -> 逾期90天以上
        else return "NORMAL"; // 正常还款（86.3%）
    }

    /**
     * 根据贷款期限选择逾期区间，确保3月、6月、12月贷款的逾期数量基本相等
     * 每个月都有逾期和逾期已还的记录
     */
    private static String selectOverdueBucketByLoanTerm(String loanTerm, String orderNo) {
        // 使用订单号生成一个稳定的随机数，确保每个月都有逾期订单
        long orderHash = Math.abs(orderNo.hashCode());
        double bucketRandom = (orderHash % 10000) / 10000.0; // 0-1之间的稳定值
        
        // 根据贷款期限调整逾期比例，确保3月、6月、12月逾期数量基本相等
        double overdueRate;
        if ("3月".equals(loanTerm)) {
            overdueRate = 0.15; // 3月贷款15%逾期率
        } else if ("6月".equals(loanTerm)) {
            overdueRate = 0.15; // 6月贷款15%逾期率
        } else if ("12月".equals(loanTerm)) {
            overdueRate = 0.15; // 12月贷款15%逾期率
        } else {
            overdueRate = 0.10; // 其他期限10%逾期率
        }
        
        // 在逾期范围内按比例分配逾期区间
        if (bucketRandom < overdueRate) {
            // 逾期后还款，按比例分配逾期区间
            double overdueRandom = (bucketRandom / overdueRate); // 重新映射到0-1范围
            
            if (overdueRandom < 0.33) return "M1_7";     // 33% -> 逾期1-7天
            else if (overdueRandom < 0.55) return "M8_15"; // 22% -> 逾期8-15天
            else if (overdueRandom < 0.70) return "M16_30"; // 15% -> 逾期16-30天
            else if (overdueRandom < 0.82) return "M30_60"; // 12% -> 逾期30-60天
            else if (overdueRandom < 0.90) return "M60_90"; // 8% -> 逾期60-90天
            else return "M90_180"; // 10% -> 逾期90天以上
        } else {
            return "NORMAL"; // 正常还款
        }
    }

    /**
     * 选择逾期区间，总逾期比例5%，确保每个月都有逾期记录
     * 逾期已还的天数分布：1-7天、7-15天、15-30天、30-60天、60-90天
     */
    private static String selectOverdueBucketWith5PercentRate(String orderNo) {
        // 使用订单号生成一个稳定的随机数，确保每个月都有逾期订单
        long orderHash = Math.abs(orderNo.hashCode());
        double bucketRandom = (orderHash % 10000) / 10000.0; // 0-1之间的稳定值
        
        // 总逾期比例5%
        double overdueRate = 0.05;
        
        // 在逾期范围内按比例分配逾期区间
        if (bucketRandom < overdueRate) {
            // 逾期后还款，按比例分配逾期区间
            double overdueRandom = (bucketRandom / overdueRate); // 重新映射到0-1范围
            
            if (overdueRandom < 0.20) return "M1_7";     // 20% -> 逾期1-7天
            else if (overdueRandom < 0.40) return "M7_15"; // 20% -> 逾期7-15天
            else if (overdueRandom < 0.60) return "M15_30"; // 20% -> 逾期15-30天
            else if (overdueRandom < 0.80) return "M30_60"; // 20% -> 逾期30-60天
            else return "M60_90"; // 20% -> 逾期60-90天
        } else {
            return "NORMAL"; // 正常还款（50%）
        }
    }

    /**
     * 选择逾期区间，总逾期比例50%，详细逾期天数分布
     * 目标：10000个订单中生成5%的逾期超过400天的订单（即500个订单）
     * 在50%的逾期订单中，超过400天的比例应该是10%
     */
    private static String selectOverdueBucketWithDetailedDistribution(String orderNo, int period) {
        // 使用真正的随机数生成器，确保均匀分布
        double bucketRandom = random.nextDouble(); // 0-1之间的真正随机值
        
        // 总逾期比例50%
        double totalOverdueRate = 1;
        
        // 在逾期范围内按比例分配逾期区间
        if (bucketRandom < totalOverdueRate) {
            // 逾期后还款，按比例分配逾期区间
            double overdueRandom = (bucketRandom / totalOverdueRate); // 重新映射到0-1范围
            
            if (period == 1) {
                // 第一期：提高400天以上逾期的比例到10%
                if (overdueRandom < 0.05) return "M1_7";     // 5% -> 逾期1-7天
                else if (overdueRandom < 0.10) return "M7_15"; // 5% -> 逾期7-15天
                else if (overdueRandom < 0.15) return "M15_30"; // 5% -> 逾期15-30天
                else if (overdueRandom < 0.20) return "M30_60"; // 5% -> 逾期30-60天
                else if (overdueRandom < 0.25) return "M60_90"; // 5% -> 逾期60-90天
                else if (overdueRandom < 0.30) return "M90_120"; // 5% -> 逾期90-120天
                else if (overdueRandom < 0.35) return "M120_150"; // 5% -> 逾期120-150天
                else if (overdueRandom < 0.40) return "M150_180"; // 5% -> 逾期150-180天
                else if (overdueRandom < 0.45) return "M180_210"; // 5% -> 逾期180-210天
                else if (overdueRandom < 0.50) return "M210_240"; // 5% -> 逾期210-240天
                else if (overdueRandom < 0.55) return "M240_270"; // 5% -> 逾期240-270天
                else if (overdueRandom < 0.60) return "M270_300"; // 5% -> 逾期270-300天
                else if (overdueRandom < 0.65) return "M300_330"; // 5% -> 逾期300-330天
                else if (overdueRandom < 0.70) return "M330_360"; // 5% -> 逾期330-360天
                else if (overdueRandom < 0.75) return "M360_390"; // 5% -> 逾期360-390天
                else if (overdueRandom < 0.80) return "M390_420"; // 5% -> 逾期390-420天
                else if (overdueRandom < 0.85) return "M420_450"; // 5% -> 逾期420-450天
                else if (overdueRandom < 0.90) return "M450_480"; // 5% -> 逾期450-480天
                else if (overdueRandom < 0.93) return "M480_510"; // 3% -> 逾期480-510天
                else if (overdueRandom < 0.96) return "M510_540"; // 3% -> 逾期510-540天
                else if (overdueRandom < 0.98) return "M540_570"; // 2% -> 逾期540-570天
                else if (overdueRandom < 0.99) return "M570_600"; // 1% -> 逾期570-600天
                else if (overdueRandom < 0.995) return "M600_630"; // 0.5% -> 逾期600-630天
                else if (overdueRandom < 0.997) return "M630_660"; // 0.2% -> 逾期630-660天
                else if (overdueRandom < 0.998) return "M660_690"; // 0.1% -> 逾期660-690天
                else if (overdueRandom < 0.999) return "M690_720"; // 0.1% -> 逾期690-720天
                else return "M720_PLUS"; // 0.1% -> 逾期720天以上
            } else {
                // 非第一期：同样提高400天以上逾期的比例到10%
                if (overdueRandom < 0.05) return "M1_7";     // 5% -> 逾期1-7天
                else if (overdueRandom < 0.10) return "M7_15"; // 5% -> 逾期7-15天
                else if (overdueRandom < 0.15) return "M15_30"; // 5% -> 逾期15-30天
                else if (overdueRandom < 0.20) return "M30_60"; // 5% -> 逾期30-60天
                else if (overdueRandom < 0.25) return "M60_90"; // 5% -> 逾期60-90天
                else if (overdueRandom < 0.30) return "M90_120"; // 5% -> 逾期90-120天
                else if (overdueRandom < 0.35) return "M120_150"; // 5% -> 逾期120-150天
                else if (overdueRandom < 0.40) return "M150_180"; // 5% -> 逾期150-180天
                else if (overdueRandom < 0.45) return "M180_210"; // 5% -> 逾期180-210天
                else if (overdueRandom < 0.50) return "M210_240"; // 5% -> 逾期210-240天
                else if (overdueRandom < 0.55) return "M240_270"; // 5% -> 逾期240-270天
                else if (overdueRandom < 0.60) return "M270_300"; // 5% -> 逾期270-300天
                else if (overdueRandom < 0.65) return "M300_330"; // 5% -> 逾期300-330天
                else if (overdueRandom < 0.70) return "M330_360"; // 5% -> 逾期330-360天
                else if (overdueRandom < 0.75) return "M360_390"; // 5% -> 逾期360-390天
                else if (overdueRandom < 0.80) return "M390_420"; // 5% -> 逾期390-420天
                else if (overdueRandom < 0.83) return "M420_450"; // 3% -> 逾期420-450天
                else if (overdueRandom < 0.86) return "M450_480"; // 3% -> 逾期450-480天
                else if (overdueRandom < 0.89) return "M480_510"; // 3% -> 逾期480-510天
                else if (overdueRandom < 0.92) return "M510_540"; // 3% -> 逾期510-540天
                else if (overdueRandom < 0.95) return "M540_570"; // 3% -> 逾期540-570天
                else if (overdueRandom < 0.97) return "M570_600"; // 2% -> 逾期570-600天
                else if (overdueRandom < 0.98) return "M600_630"; // 1% -> 逾期600-630天
                else if (overdueRandom < 0.99) return "M630_660"; // 1% -> 逾期630-660天
                else if (overdueRandom < 0.995) return "M660_690"; // 0.5% -> 逾期660-690天
                else if (overdueRandom < 0.998) return "M690_720"; // 0.3% -> 逾期690-720天
                else return "M720_PLUS"; // 0.2% -> 逾期720天以上
            }
        } else {
            return "NORMAL"; // 正常还款（50%）
        }
    }

    /**
     * 判断该期还款计划是否应该逾期
     */
    private static boolean shouldPlanOverdue(CustomerRepayPlan plan, String overdueBucket, LocalDate now) {
        if (overdueBucket == null) return false;

        // 根据期数和逾期区间决定是否逾期
        // 例如：如果选择M2逾期，则前2期正常还款，第3期开始逾期
        int planTerm = plan.getBillTenor().intValue();

        switch (overdueBucket) {
            case "M1": return planTerm >= 1;
            case "M2": return planTerm >= 2;
            case "M3": return planTerm >= 3;
            case "M4": return planTerm >= 4;
            case "M5": return planTerm >= 5;
            case "M6": return planTerm >= 6;
            default: return false;
        }
    }

    /**
     * 应用逾期逻辑（支持新的逾期区间和提前结清）
     */
    private static void applyOverdueLogic(CustomerRepayPlan plan, CustomerOrder order,
                                          LocalDate dueDate, LocalDate now, String overdueBucket, List<CustomerRepayPlan> allPlans) {
        
//        // 检查是否应该提前结清（5%的概率，在还了一半期数后）
//        if (shouldEarlySettle(order, plan)) {
//            applyEarlySettlementLogic(plan, dueDate, allPlans, order);
//            return;
//        }

        // 根据新的逾期区间处理
        if ("NORMAL".equals(overdueBucket)) {
            // 正常还款，确保实际还款日期小于等于2025-09-30
            LocalDate maxRepayDate = LocalDate.of(2025, 9, 30);
            LocalDate actualRepayDate = dueDate.isAfter(maxRepayDate) ? maxRepayDate : dueDate;
            
            plan.setRepayStatus("已结清");
            plan.setActualRepayDate(actualRepayDate);
            plan.setActualRepayMoney(plan.getNowPayAmount());
            plan.setOverdueDays(0);
            plan.setActualPrincipal(plan.getNowPayPrincipal());
            plan.setActualInterest(plan.getNowPayInterest());
            plan.setPenaltyInterest(BigDecimal.ZERO);
        } else {
            // 逾期后还款
            LocalDate actualRepayDate = calculateActualRepayDateByBucket(dueDate, overdueBucket);
            plan.setRepayStatus("已结清");
            plan.setActualRepayDate(actualRepayDate);

            long actualOverdueDays = actualRepayDate.toEpochDay() - dueDate.toEpochDay();
            plan.setOverdueDays((int) actualOverdueDays);

            // 计算罚息
            if (actualOverdueDays > 0) {
                BigDecimal penaltyRate = plan.getRate().divide(new BigDecimal("365"), 10, RoundingMode.HALF_UP)
                        .multiply(new BigDecimal("1.5"));
                BigDecimal penaltyInterest = plan.getNowPayAmount()
                        .multiply(penaltyRate)
                        .multiply(BigDecimal.valueOf(actualOverdueDays))
                        .setScale(2, RoundingMode.HALF_UP);
                plan.setPenaltyInterest(penaltyInterest);
            } else {
                plan.setPenaltyInterest(BigDecimal.ZERO);
            }
            
            plan.setActualPrincipal(plan.getNowPayPrincipal());
            plan.setActualInterest(plan.getNowPayInterest());
            plan.setActualRepayMoney(plan.getNowPayAmount().add(plan.getPenaltyInterest()));
            plan.setNowPayAmount(plan.getNowPayAmount().add(plan.getPenaltyInterest()));
        }
    }

    /**
     * 应用逾期逻辑（5%逾期率，还款日期在2025-10-01之前）
     * 逾期已还的天数分布：1-7天、7-15天、15-30天、30-60天、60-90天
     */
    private static void applyOverdueLogicWith5Percent(CustomerRepayPlan plan, CustomerOrder order,
                                                      LocalDate dueDate, LocalDate now, String overdueBucket, List<CustomerRepayPlan> allPlans) {
        
        // 根据新的逾期区间处理
        if ("NORMAL".equals(overdueBucket)) {
            // 正常还款，确保实际还款日期小于等于2025-09-30
            LocalDate maxRepayDate = LocalDate.of(2025, 9, 30);
            LocalDate actualRepayDate = dueDate.isAfter(maxRepayDate) ? maxRepayDate : dueDate;
            
            plan.setRepayStatus("已结清");
            plan.setActualRepayDate(actualRepayDate);
            plan.setActualRepayMoney(plan.getNowPayAmount());
            plan.setOverdueDays(0);
            plan.setActualPrincipal(plan.getNowPayPrincipal());
            plan.setActualInterest(plan.getNowPayInterest());
            plan.setPenaltyInterest(BigDecimal.ZERO);
        } else {
            // 逾期后还款，确保还款日期在2025-10-01之前
            LocalDate actualRepayDate = calculateActualRepayDateByBucket5Percent(dueDate, overdueBucket);
            plan.setRepayStatus("已结清");
            plan.setActualRepayDate(actualRepayDate);

            long actualOverdueDays = actualRepayDate.toEpochDay() - dueDate.toEpochDay();
            plan.setOverdueDays((int) actualOverdueDays);

            // 计算罚息
            if (actualOverdueDays > 0) {
                BigDecimal penaltyRate = plan.getRate().divide(new BigDecimal("365"), 10, RoundingMode.HALF_UP)
                        .multiply(new BigDecimal("1.5"));
                BigDecimal penaltyInterest = plan.getNowPayAmount()
                        .multiply(penaltyRate)
                        .multiply(BigDecimal.valueOf(actualOverdueDays))
                        .setScale(2, RoundingMode.HALF_UP);
                plan.setPenaltyInterest(penaltyInterest);
            } else {
                plan.setPenaltyInterest(BigDecimal.ZERO);
            }
            
            plan.setActualPrincipal(plan.getNowPayPrincipal());
            plan.setActualInterest(plan.getNowPayInterest());
            plan.setActualRepayMoney(plan.getNowPayAmount().add(plan.getPenaltyInterest()));
            plan.setNowPayAmount(plan.getNowPayAmount().add(plan.getPenaltyInterest()));
        }
    }

    /**
     * 应用逾期逻辑（详细逾期天数分布，还款日期在2025-10-01之前）
     * 支持最高720天的逾期天数分布
     */
    private static void applyOverdueLogicWithDetailedDistribution(CustomerRepayPlan plan, CustomerOrder order,
                                                                  LocalDate dueDate, LocalDate now, String overdueBucket, List<CustomerRepayPlan> allPlans) {
        
        // 根据新的逾期区间处理
        if ("NORMAL".equals(overdueBucket)) {
            // 正常还款，确保实际还款日期小于等于2025-09-30
            LocalDate maxRepayDate = LocalDate.of(2025, 9, 30);
            LocalDate actualRepayDate = dueDate.isAfter(maxRepayDate) ? maxRepayDate : dueDate;
            
            plan.setRepayStatus("已结清");
            plan.setActualRepayDate(actualRepayDate);
            plan.setActualRepayMoney(plan.getNowPayAmount());
            plan.setOverdueDays(0);
            plan.setActualPrincipal(plan.getNowPayPrincipal());
            plan.setActualInterest(plan.getNowPayInterest());
            plan.setPenaltyInterest(BigDecimal.ZERO);
        } else {
            // 逾期后还款，确保还款日期在2025-10-01之前
            LocalDate actualRepayDate = calculateActualRepayDateByBucketDetailed(dueDate, overdueBucket);
            plan.setRepayStatus("已结清");
            plan.setActualRepayDate(actualRepayDate);

            long actualOverdueDays = actualRepayDate.toEpochDay() - dueDate.toEpochDay();
            plan.setOverdueDays((int) actualOverdueDays);

            // 计算罚息
            if (actualOverdueDays > 3) {
                BigDecimal penaltyRate = plan.getRate().divide(new BigDecimal("365"), 10, RoundingMode.HALF_UP)
                        .multiply(new BigDecimal("1.5"));
                BigDecimal penaltyInterest = plan.getNowPayAmount()
                        .multiply(penaltyRate)
                        .multiply(BigDecimal.valueOf(actualOverdueDays))
                        .setScale(2, RoundingMode.HALF_UP);
                plan.setPenaltyInterest(penaltyInterest);
            } else {
                plan.setPenaltyInterest(BigDecimal.ZERO);
            }
            
            plan.setActualPrincipal(plan.getNowPayPrincipal());
            plan.setActualInterest(plan.getNowPayInterest());
            plan.setActualRepayMoney(plan.getNowPayAmount().add(plan.getPenaltyInterest()));
            plan.setNowPayAmount(plan.getNowPayAmount().add(plan.getPenaltyInterest()));
        }
    }


    /**
     * 计算逾期天数
     */
    private static long calculateOverdueDays(LocalDate dueDate, LocalDate now, String overdueBucket) {
        switch (overdueBucket) {
            case "M1": return 15 + random.nextInt(16); // 15-30天
            case "M2": return 31 + random.nextInt(30); // 31-60天
            case "M3": return 61 + random.nextInt(30); // 61-90天
            case "M4": return 91 + random.nextInt(30); // 91-120天
            case "M5": return 121 + random.nextInt(30); // 121-150天
            case "M6": return 151 + random.nextInt(30); // 151-180天
            default: return 1 + random.nextInt(30); // 默认1-30天
        }
    }

    /**
     * 根据新的逾期区间计算实际还款日期
     * 确保实际还款日期只能小于等于2025-09-30
     */
    private static LocalDate calculateActualRepayDateByBucket(LocalDate dueDate, String overdueBucket) {
        LocalDate maxRepayDate = LocalDate.of(2025, 9, 30); // 最大还款日期
        LocalDate actualRepayDate;
        
        switch (overdueBucket) {
            case "M1_7": 
                actualRepayDate = dueDate.plusDays(1 + random.nextInt(7)); // 1-7天后还款
                break;
            case "M8_15": 
                actualRepayDate = dueDate.plusDays(8 + random.nextInt(8)); // 8-15天后还款
                break;
            case "M16_30": 
                actualRepayDate = dueDate.plusDays(16 + random.nextInt(15)); // 16-30天后还款
                break;
            case "M30_60": 
                actualRepayDate = dueDate.plusDays(30 + random.nextInt(31)); // 30-60天后还款
                break;
            case "M60_90": 
                actualRepayDate = dueDate.plusDays(60 + random.nextInt(31)); // 60-90天后还款
                break;
            case "M90_180": 
                actualRepayDate = dueDate.plusDays(90 + random.nextInt(91)); // 90-180天后还款
                break;
            default: 
                return dueDate; // 正常还款
        }
        
        // 确保实际还款日期不超过2025-09-30
        if (actualRepayDate.isAfter(maxRepayDate)) {
            actualRepayDate = maxRepayDate;
        }
        
        return actualRepayDate;
    }

    /**
     * 根据5%逾期率的逾期区间计算实际还款日期
     * 确保实际还款日期在2025-10-01之前
     * 逾期已还的天数分布：1-7天、7-15天、15-30天、30-60天、60-90天
     */
    private static LocalDate calculateActualRepayDateByBucket5Percent(LocalDate dueDate, String overdueBucket) {
        LocalDate maxRepayDate = LocalDate.of(2025, 9, 30); // 最大还款日期（2025-10-01之前）
        LocalDate actualRepayDate;
        
        switch (overdueBucket) {
            case "M1_7": 
                actualRepayDate = dueDate.plusDays(1 + random.nextInt(7)); // 1-7天后还款
                break;
            case "M7_15": 
                actualRepayDate = dueDate.plusDays(7 + random.nextInt(9)); // 7-15天后还款
                break;
            case "M15_30": 
                actualRepayDate = dueDate.plusDays(15 + random.nextInt(16)); // 15-30天后还款
                break;
            case "M30_60": 
                actualRepayDate = dueDate.plusDays(30 + random.nextInt(31)); // 30-60天后还款
                break;
            case "M60_90": 
                actualRepayDate = dueDate.plusDays(60 + random.nextInt(31)); // 60-90天后还款
                break;
            default: 
                return dueDate; // 正常还款
        }
        
        // 确保实际还款日期在2025-10-01之前
        if (actualRepayDate.isAfter(maxRepayDate)) {
            actualRepayDate = maxRepayDate;
        }
        
        return actualRepayDate;
    }

    /**
     * 根据详细逾期天数分布计算实际还款日期
     * 确保实际还款日期在2025-10-01之前
     * 支持最高720天的逾期天数分布
     */
    private static LocalDate calculateActualRepayDateByBucketDetailed(LocalDate dueDate, String overdueBucket) {
        LocalDate maxRepayDate = LocalDate.of(2025, 9, 30); // 最大还款日期（2025-10-01之前）
        LocalDate actualRepayDate;
        
        switch (overdueBucket) {
            case "M1_7": 
                actualRepayDate = dueDate.plusDays(1 + random.nextInt(7)); // 1-7天后还款
                break;
            case "M7_15": 
                actualRepayDate = dueDate.plusDays(7 + random.nextInt(9)); // 7-15天后还款
                break;
            case "M15_30": 
                actualRepayDate = dueDate.plusDays(15 + random.nextInt(16)); // 15-30天后还款
                break;
            case "M30_60": 
                actualRepayDate = dueDate.plusDays(30 + random.nextInt(31)); // 30-60天后还款
                break;
            case "M60_90": 
                actualRepayDate = dueDate.plusDays(60 + random.nextInt(31)); // 60-90天后还款
                break;
            case "M90_120": 
                actualRepayDate = dueDate.plusDays(90 + random.nextInt(31)); // 90-120天后还款
                break;
            case "M120_150": 
                actualRepayDate = dueDate.plusDays(120 + random.nextInt(31)); // 120-150天后还款
                break;
            case "M150_180": 
                actualRepayDate = dueDate.plusDays(150 + random.nextInt(31)); // 150-180天后还款
                break;
            case "M180_210": 
                actualRepayDate = dueDate.plusDays(180 + random.nextInt(31)); // 180-210天后还款
                break;
            case "M210_240": 
                actualRepayDate = dueDate.plusDays(210 + random.nextInt(31)); // 210-240天后还款
                break;
            case "M240_270": 
                actualRepayDate = dueDate.plusDays(240 + random.nextInt(31)); // 240-270天后还款
                break;
            case "M270_300": 
                actualRepayDate = dueDate.plusDays(270 + random.nextInt(31)); // 270-300天后还款
                break;
            case "M300_330": 
                actualRepayDate = dueDate.plusDays(300 + random.nextInt(31)); // 300-330天后还款
                break;
            case "M330_360": 
                actualRepayDate = dueDate.plusDays(330 + random.nextInt(31)); // 330-360天后还款
                break;
            case "M360_390": 
                actualRepayDate = dueDate.plusDays(360 + random.nextInt(31)); // 360-390天后还款
                break;
            case "M390_420": 
                actualRepayDate = dueDate.plusDays(390 + random.nextInt(31)); // 390-420天后还款
                break;
            case "M420_450": 
                actualRepayDate = dueDate.plusDays(420 + random.nextInt(31)); // 420-450天后还款
                break;
            case "M450_480": 
                actualRepayDate = dueDate.plusDays(450 + random.nextInt(31)); // 450-480天后还款
                break;
            case "M480_510": 
                actualRepayDate = dueDate.plusDays(480 + random.nextInt(31)); // 480-510天后还款
                break;
            case "M510_540": 
                actualRepayDate = dueDate.plusDays(510 + random.nextInt(31)); // 510-540天后还款
                break;
            case "M540_570": 
                actualRepayDate = dueDate.plusDays(540 + random.nextInt(31)); // 540-570天后还款
                break;
            case "M570_600": 
                actualRepayDate = dueDate.plusDays(570 + random.nextInt(31)); // 570-600天后还款
                break;
            case "M600_630": 
                actualRepayDate = dueDate.plusDays(600 + random.nextInt(31)); // 600-630天后还款
                break;
            case "M630_660": 
                actualRepayDate = dueDate.plusDays(630 + random.nextInt(31)); // 630-660天后还款
                break;
            case "M660_690": 
                actualRepayDate = dueDate.plusDays(660 + random.nextInt(31)); // 660-690天后还款
                break;
            case "M690_720": 
                actualRepayDate = dueDate.plusDays(690 + random.nextInt(31)); // 690-720天后还款
                break;
            case "M720_PLUS": 
                actualRepayDate = dueDate.plusDays(720 + random.nextInt(31)); // 720天以上还款
                break;
            default: 
                return dueDate; // 正常还款
        }
        
        // 确保实际还款日期在2025-10-01之前
        if (actualRepayDate.isAfter(maxRepayDate)) {
            actualRepayDate = maxRepayDate;
        }
        
        return actualRepayDate;
    }

    /**
     * 计算实际还款日期（保留原方法以兼容性）
     */
    private static LocalDate calculateActualRepayDate(LocalDate dueDate, String overdueBucket) {
        switch (overdueBucket) {
            case "M1": return dueDate.plusDays(3 + random.nextInt(16)); // 3-30天后还款
            case "M2": return dueDate.plusDays(31 + random.nextInt(30)); // 31-60天后还款
            case "M3": return dueDate.plusDays(61 + random.nextInt(30)); // 61-90天后还款
            case "M4": return dueDate.plusDays(91 + random.nextInt(30)); // 91-120天后还款
            case "M5": return dueDate.plusDays(121 + random.nextInt(30)); // 121-150天后还款
            case "M6": return dueDate.plusDays(151 + random.nextInt(30)); // 151-180天后还款
            default: return dueDate.plusDays(1 + random.nextInt(30)); // 默认1-30天后还款
        }
    }

    /**
     * 判断是否应该提前结清（5%概率，在bill_tenor到loan_term一半左右时）
     */
    private static boolean shouldEarlySettle(CustomerOrder order, CustomerRepayPlan plan) {
        int totalTerms = Integer.parseInt(order.getLoanTerm().replace("月", ""));
        int currentTerm = plan.getBillTenor().intValue();
        
        // 在bill_tenor到loan_term一半左右时可能提前结清
        // 允许在接近一半期数时就开始提前结清
        if (currentTerm < (totalTerms / 2)) {
            return false;
        }
        
        // 5%的概率提前结清
        return random.nextDouble() < 0.05;
    }

    /**
     * 应用提前结清逻辑
     */
    private static void applyEarlySettlementLogic(CustomerRepayPlan plan, LocalDate dueDate, List<CustomerRepayPlan> allPlans, CustomerOrder order) {
        // 提前结清：当bill_tenor到loan_term一半左右时，把剩余期数全部结清
        // 实际还款日期在due_date之前，但不超过2025-09-30
        LocalDate maxRepayDate = LocalDate.of(2025, 9, 30);
        LocalDate actualRepayDate = dueDate.minusDays(1 + random.nextInt(10)); // 提前1-10天还款
        
        // 确保实际还款日期不超过2025-09-30
        if (actualRepayDate.isAfter(maxRepayDate)) {
            actualRepayDate = maxRepayDate;
        }
        
        // 计算剩余未还所有期数的应还本金之和
        BigDecimal totalRemainingPrincipal = BigDecimal.ZERO;
        int currentTerm = plan.getBillTenor().intValue();
        int totalTerms = Integer.parseInt(order.getLoanTerm().replace("月", ""));
        
        // 计算从当前期到最后一期的所有应还本金（剩余未还的期数）
        for (int i = currentTerm; i <= totalTerms; i++) {
            final int termIndex = i; // 创建final变量用于lambda表达式
            // 找到对应期数的还款计划
            CustomerRepayPlan remainingPlan = allPlans.stream()
                    .filter(p -> p.getBillTenor().intValue() == termIndex)
                    .findFirst()
                    .orElse(null);
            
            if (remainingPlan != null) {
                totalRemainingPrincipal = totalRemainingPrincipal.add(remainingPlan.getNowPayPrincipal());
            }
        }
        
        // 提前结清的这期的实际还款本金 = 剩余未还所有期数的应还本金之和
        plan.setActualPrincipal(totalRemainingPrincipal);
        
        // 提前结清的这期的实际还款利息 = 本期的应还利息（没有罚息）
        plan.setActualInterest(plan.getNowPayInterest());
        
        // 提前结清的这期的实际还款金额 = 实际还款本金 + 实际还款利息
        BigDecimal actualRepayMoney = totalRemainingPrincipal.add(plan.getNowPayInterest());
        plan.setActualRepayMoney(actualRepayMoney);
        
        // 设置提前结清这期的状态和日期
        plan.setRepayStatus("已结清");
        plan.setActualRepayDate(actualRepayDate);
        plan.setOverdueDays(0);
        plan.setPenaltyInterest(BigDecimal.ZERO); // 没有罚息
        
        // 将剩余期数的还款计划也标记为已结清，结清后的期数实还金额都是0
        for (int i = currentTerm + 1; i <= totalTerms; i++) {
            final int termIndex = i; // 创建final变量用于lambda表达式
            CustomerRepayPlan remainingPlan = allPlans.stream()
                    .filter(p -> p.getBillTenor().intValue() == termIndex)
                    .findFirst()
                    .orElse(null);
            
            if (remainingPlan != null) {
                remainingPlan.setRepayStatus("已结清");
                remainingPlan.setActualRepayDate(actualRepayDate);
                remainingPlan.setActualRepayMoney(BigDecimal.ZERO); // 结清后的期数实还金额都是0
                remainingPlan.setActualPrincipal(BigDecimal.ZERO); // 本金已在当前期还清
                remainingPlan.setActualInterest(BigDecimal.ZERO); // 利息已在当前期还清
                remainingPlan.setOverdueDays(0);
                remainingPlan.setPenaltyInterest(BigDecimal.ZERO); // 没有罚息
            }
        }
    }

    /**
     * 判断是否应该继续逾期（迁徙率逻辑）
     */
    private static boolean shouldContinueOverdue(String overdueBucket) {
        // 根据迁徙率决定是否继续逾期（迁徙率都小于100%）
        switch (overdueBucket) {
            case "M1":
                return random.nextDouble() < MIGRATION_RATES.get("M1_M2"); // 10%
            case "M2":
                return random.nextDouble() < MIGRATION_RATES.get("M2_M3"); // 40%
            case "M3":
                return random.nextDouble() < MIGRATION_RATES.get("M3_M4"); // 50%
            case "M4":
                return random.nextDouble() < MIGRATION_RATES.get("M4_M5"); // 60%
            case "M5":
                return random.nextDouble() < MIGRATION_RATES.get("M5_M6"); // 70%
            default:
                return random.nextDouble() < 0.05; // M6+有75%概率继续逾期
        }
    }

    /**
     * 更新订单状态和剩余金额
     */
    private static void updateOrderStatusAndRemainAmount(CustomerOrder order, List<CustomerRepayPlan> plans, LocalDate now) {
        // 检查所有期数的还款状态
        boolean allSettled = plans.stream().allMatch(plan -> "已结清".equals(plan.getRepayStatus()));

        // 设置订单状态
        order.setStatus(allSettled ? "已结清" : "未结清");

        if (allSettled) {
            // 如果所有期数都已结清，设置结清日期为最后一笔实际还款日期
            LocalDate lastActualRepayDate = plans.stream()
                    .filter(plan -> plan.getActualRepayDate() != null)
                    .map(CustomerRepayPlan::getActualRepayDate)
                    .max(LocalDate::compareTo)
                    .orElse(null);

            if (lastActualRepayDate != null) {
                order.setSettleDate(lastActualRepayDate);
            }
            order.setRemainPayAmount(BigDecimal.ZERO);
        } else {
            // 计算剩余金额 = 贷款金额 - 已还本金
            BigDecimal totalPaidPrincipal = plans.stream()
                    .filter(plan -> "已结清".equals(plan.getRepayStatus()))
                    .map(CustomerRepayPlan::getActualPrincipal)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            BigDecimal remainAmount = order.getLoanAmount().subtract(totalPaidPrincipal);
            order.setRemainPayAmount(remainAmount.max(BigDecimal.ZERO)); // 确保不为负数

            order.setSettleDate(null);
        }

        // 设置放款时间等于客户创建时间
        order.setFrTime(order.getFrTime());
    }

    /**
     * 根据放款日期获取产品名称（按权重分布）
     */
    public static String getProductNameByDate(LocalDate loanDate) {
        // 2023年7月-12月：只有浩瀚小贷
        if (loanDate.isBefore(START_DATE.plusMonths(HAOHAN_ONLY_MONTHS))) {
            return "浩瀚小贷";
        }

        // 2024年1月后：多产品分布
        double randomValue = random.nextDouble();
        if (randomValue < PRODUCT_DISTRIBUTION.get("浩瀚小贷")) {
            return "浩瀚小贷";
        } else if (randomValue < PRODUCT_DISTRIBUTION.get("浩瀚小贷") + PRODUCT_DISTRIBUTION.get("盈峰小贷")) {
            return "盈峰小贷";
        } else if (randomValue < PRODUCT_DISTRIBUTION.get("浩瀚小贷") + PRODUCT_DISTRIBUTION.get("盈峰小贷") + PRODUCT_DISTRIBUTION.get("新网银行")) {
            return "新网银行";
        } else {
            return "江山小贷";
        }
    }

    /**
     * 生成完整的数据集并批量插入数据库（满足所有要求）
     */
    public DataGenerationResult generateCompleteDataSetWithBatchInsert() {
        // 清空现有数据
        DataGenerationResult result = new DataGenerationResult();

        // 批量插入缓存列表（线程安全）
        List<CustomerInfo> customerBatch = Collections.synchronizedList(new ArrayList<>());
        List<CustomerOrder> orderBatch = Collections.synchronizedList(new ArrayList<>());
        List<CustomerRepayPlan> repayPlanBatch = Collections.synchronizedList(new ArrayList<>());

        // 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);

        // 原子变量用于线程安全的统计
        AtomicReference<BigDecimal> totalGeneratedAmount = new AtomicReference<>(BigDecimal.ZERO);
        AtomicReference<BigDecimal> totalOutstandingAmount = new AtomicReference<>(BigDecimal.ZERO);
        AtomicReference<BigDecimal> haohanOutstandingAmount = new AtomicReference<>(BigDecimal.ZERO);
        AtomicInteger totalProcessedOrders = new AtomicInteger(0);
        AtomicInteger batchCount = new AtomicInteger(0);

        // 从2023年7月到当前月份，每月生成数据
        LocalDate currentDate = LocalDate.now();
//        LocalDate currentDate = LocalDate.now().minusMonths(1); // 修改为上个月
        LocalDate month = START_DATE;

        log.info("开始生成数据（目标：500万放款总额）...");
        log.info("使用多线程池，线程数: {}", THREAD_POOL_SIZE);

        try {
            while (month.isBefore(currentDate)) {
                // 计算该月应该生成的订单数量（递增，大规模数据）
                int monthsFromStart = (int) (month.toEpochDay() - START_DATE.toEpochDay()) / 30;

                int baseOrders = 300; // 基础订单数（26个月，目标5000万，10000条订单）
                int monthlyOrders = baseOrders + (monthsFromStart * 8); // 每月递增8个订单


                log.info("生成 {} 月份数据，订单数量: {}", month, monthlyOrders);

                // 使用多线程生成该月数据
                List<Future<OrderDataPackage>> futures = new ArrayList<>();

                // 将订单分成多个批次，每个线程处理一部分
                int ordersPerThread = Math.max(1, monthlyOrders / THREAD_POOL_SIZE);
                int remainingOrders = monthlyOrders;

                while (remainingOrders > 0) {
                    int ordersForThisThread = Math.min(ordersPerThread, remainingOrders);
                    final int finalOrdersForThisThread = ordersForThisThread;
                    final LocalDate finalMonth = month;

                    Future<OrderDataPackage> future = executorService.submit(() ->
                            generateOrderDataBatch(finalMonth, finalOrdersForThisThread));
                    futures.add(future);

                    remainingOrders -= ordersForThisThread;
                }

                // 等待所有线程完成并收集结果
                for (Future<OrderDataPackage> future : futures) {
                    try {
                        OrderDataPackage orderPackage = future.get();

                        // 添加到批量插入缓存
                        customerBatch.addAll(orderPackage.getCustomers());
                        orderBatch.addAll(orderPackage.getOrders());
                        repayPlanBatch.addAll(orderPackage.getRepayPlans());

                        // 更新统计（原子操作）
                        totalGeneratedAmount.updateAndGet(amount -> amount.add(orderPackage.getTotalLoanAmount()));
                        totalOutstandingAmount.updateAndGet(amount -> amount.add(orderPackage.getTotalOutstandingAmount()));
                        haohanOutstandingAmount.updateAndGet(amount -> amount.add(orderPackage.getHaohanOutstandingAmount()));
                        totalProcessedOrders.addAndGet(orderPackage.getOrderCount());

                        // 检查是否需要批量插入
                        if (customerBatch.size() >= BATCH_SIZE) {
                            processBatchInsert(customerBatch, orderBatch, repayPlanBatch,
                                    batchCount, totalProcessedOrders, totalGeneratedAmount, totalOutstandingAmount);
                        }

                    } catch (Exception e) {
                        log.error("处理订单数据时发生异常", e);
                    }
                }

                month = month.plusMonths(1);
            }

            // 插入剩余的数据（如果缓存中还有数据）
            if (!customerBatch.isEmpty()) {
                processBatchInsert(customerBatch, orderBatch, repayPlanBatch,
                        batchCount, totalProcessedOrders, totalGeneratedAmount, totalOutstandingAmount);
            }

            // 输出最终统计信息
            log.info("\n=== 数据生成完成 ===");
            log.info("总处理订单数: {}", totalProcessedOrders.get());
            log.info("总批次: {}", batchCount.get());
            log.info("总投放金额: {} 亿", totalGeneratedAmount.get().divide(new BigDecimal("100000000"), 2, RoundingMode.HALF_UP));
            log.info("在途余额: {} 亿", totalOutstandingAmount.get().divide(new BigDecimal("100000000"), 2, RoundingMode.HALF_UP));
            log.info("浩瀚小贷在途余额: {} 亿", haohanOutstandingAmount.get().divide(new BigDecimal("100000000"), 2, RoundingMode.HALF_UP));

        } finally {
            // 关闭线程池
            executorService.shutdown();
        }

        return result;
    }

    /**
     * 批量插入数据到数据库（单条插入）
     */
    private void batchInsertData(CustomerInfo customer, CustomerOrder order, List<CustomerRepayPlan> repayPlans) {
        try {
            // 插入客户信息
            customerInfoMapper.insert(customer);

            // 插入订单信息
            customerOrderMapper.insert(order);

            // 批量插入还款计划
            for (CustomerRepayPlan plan : repayPlans) {
                customerRepayPlanMapper.insert(plan);
            }

        } catch (Exception e) {
            System.err.println("插入数据失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 批量插入数据到数据库（真正的批量插入）
     */
    @Transactional(rollbackFor = Exception.class)
    public void batchInsertDataBatch(List<CustomerInfo> customers, List<CustomerOrder> orders, List<CustomerRepayPlan> repayPlans) {
        try {
            log.info("开始批量插入数据，客户数: {}, 订单数: {}, 还款计划数: {}",
                    customers.size(), orders.size(), repayPlans.size());

            // 分批插入以避免连接超时
            insertCustomersInBatches(customers);
            insertOrdersInBatches(orders);
            insertRepayPlansInBatches(repayPlans);

            log.info("批量插入数据完成");
        } catch (Exception e) {
            log.error("批量插入失败", e);
            throw e; // 重新抛出异常确保事务回滚
        }
    }

    /**
     * 生成完整的数据集（内存版本，不插入数据库）
     */
    public static DataGenerationResult generateCompleteDataSet() {
        DataGenerationResult result = new DataGenerationResult();
        List<CustomerInfo> allCustomers = new ArrayList<>();
        List<CustomerOrder> allOrders = new ArrayList<>();
        List<CustomerRepayPlan> allRepayPlans = new ArrayList<>();

        // 从2023年7月到当前月份，每月生成数据
        LocalDate currentDate = LocalDate.now();
        LocalDate month = START_DATE;

        BigDecimal totalGeneratedAmount = BigDecimal.ZERO;
        BigDecimal totalOutstandingAmount = BigDecimal.ZERO;
        BigDecimal haohanOutstandingAmount = BigDecimal.ZERO;

        while (!month.isAfter(currentDate)) {
            // 计算该月应该生成的订单数量（递增）
            int monthsFromStart = (int) (month.toEpochDay() - START_DATE.toEpochDay()) / 30;
            int baseOrders = 50; // 基础订单数
            int monthlyOrders = baseOrders + (monthsFromStart * 5); // 每月递增5个订单

            // 生成该月数据
            List<CustomerOrder> monthlyOrdersList = generateMonthlyData(month, monthlyOrders);

            // 为每个订单生成完整的客户信息和还款计划
            for (CustomerOrder order : monthlyOrdersList) {
                CustomerInfo customer = generateCustomerInfo(month);

                // 设置客户创建时间
                order.setFrTime(customer.getCreatedTime().substring(0, 10));

                // 生成还款计划
                List<CustomerRepayPlan> repayPlans = generateRepayPlan(order);

                // 设置订单客户ID
                order.setCustomerId(customer.getId());

                // 更新统计
                totalGeneratedAmount = totalGeneratedAmount.add(order.getLoanAmount());
                if ("未结清".equals(order.getStatus())) {
                    totalOutstandingAmount = totalOutstandingAmount.add(order.getRemainPayAmount());
                    if ("浩瀚小贷".equals(order.getProductName())) {
                        haohanOutstandingAmount = haohanOutstandingAmount.add(order.getRemainPayAmount());
                    }
                }

                allCustomers.add(customer);
                allOrders.add(order);
                allRepayPlans.addAll(repayPlans);
            }

            month = month.plusMonths(1);
        }

        result.setCustomers(allCustomers);
        result.setOrders(allOrders);
        result.setRepayPlans(allRepayPlans);

        // 输出统计信息
        log.info("数据生成完成:");
        log.info("总投放金额: " + totalGeneratedAmount);
        log.info("在途余额: " + totalOutstandingAmount);
        log.info("浩瀚小贷在途余额: " + haohanOutstandingAmount);

        return result;
    }

    /**
     * 计算Vintage逾期率
     */
    public static Map<String, VintageAnalysis> calculateVintageAnalysis(List<CustomerOrder> orders, List<CustomerRepayPlan> repayPlans) {
        Map<String, VintageAnalysis> vintageResults = new HashMap<>();
//        LocalDate now = LocalDate.now();
        LocalDate now=LocalDate.of(2025, 9, 30);

        // 按Vintage（放款月份）分组
        Map<String, List<CustomerOrder>> vintageGroups = orders.stream()
                .collect(Collectors.groupingBy(order -> order.getFrTime().substring(0, 7)));

        for (Map.Entry<String, List<CustomerOrder>> entry : vintageGroups.entrySet()) {
            String vintage = entry.getKey();
            List<CustomerOrder> vintageOrders = entry.getValue();

            VintageAnalysis analysis = new VintageAnalysis();
            analysis.setVintage(vintage);

            // 计算初始发放总额
            BigDecimal initialAmount = vintageOrders.stream()
                    .map(CustomerOrder::getLoanAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            analysis.setInitialAmount(initialAmount);

            // 计算各逾期阶段的余额
            BigDecimal overdue0Plus = calculateOverdueAmount(vintageOrders, repayPlans, 0, now);
            BigDecimal overdue30Plus = calculateOverdueAmount(vintageOrders, repayPlans, 30, now);
            BigDecimal overdue60Plus = calculateOverdueAmount(vintageOrders, repayPlans, 60, now);
            BigDecimal overdue90Plus = calculateOverdueAmount(vintageOrders, repayPlans, 90, now);

            analysis.setOverdue0Plus(overdue0Plus);
            analysis.setOverdue30Plus(overdue30Plus);
            analysis.setOverdue60Plus(overdue60Plus);
            analysis.setOverdue90Plus(overdue90Plus);

            // 计算逾期率
            if (initialAmount.compareTo(BigDecimal.ZERO) > 0) {
                analysis.setOverdue0PlusRate(overdue0Plus.divide(initialAmount, 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));
                analysis.setOverdue30PlusRate(overdue30Plus.divide(initialAmount, 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));
                analysis.setOverdue60PlusRate(overdue60Plus.divide(initialAmount, 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));
                analysis.setOverdue90PlusRate(overdue90Plus.divide(initialAmount, 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));
            }

            vintageResults.put(vintage, analysis);
        }

        return vintageResults;
    }

    /**
     * 计算指定逾期天数的未偿还本金余额
     */
    private static BigDecimal calculateOverdueAmount(List<CustomerOrder> vintageOrders, List<CustomerRepayPlan> repayPlans,
                                                     int overdueDays, LocalDate now) {
        Set<String> vintageOrderNos = vintageOrders.stream()
                .map(CustomerOrder::getOrderNo)
                .collect(Collectors.toSet());

        return repayPlans.stream()
                .filter(plan -> vintageOrderNos.contains(plan.getOrderNo()))
                .filter(plan -> {
                    if (plan.getActualRepayDate() == null) {
                        // 未还款的计划，检查是否逾期超过指定天数
                        long daysOverdue = now.toEpochDay() - plan.getDueDate().toEpochDay();
                        return daysOverdue > overdueDays;
                    }
                    return false;
                })
                .map(plan -> plan.getNowPayPrincipal())
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    /**
     * Vintage分析结果类
     */
    public static class VintageAnalysis {
        private String vintage;
        private BigDecimal initialAmount;
        private BigDecimal overdue0Plus;
        private BigDecimal overdue30Plus;
        private BigDecimal overdue60Plus;
        private BigDecimal overdue90Plus;
        private BigDecimal overdue0PlusRate;
        private BigDecimal overdue30PlusRate;
        private BigDecimal overdue60PlusRate;
        private BigDecimal overdue90PlusRate;

        // Getters and Setters
        public String getVintage() { return vintage; }
        public void setVintage(String vintage) { this.vintage = vintage; }
        public BigDecimal getInitialAmount() { return initialAmount; }
        public void setInitialAmount(BigDecimal initialAmount) { this.initialAmount = initialAmount; }
        public BigDecimal getOverdue0Plus() { return overdue0Plus; }
        public void setOverdue0Plus(BigDecimal overdue0Plus) { this.overdue0Plus = overdue0Plus; }
        public BigDecimal getOverdue30Plus() { return overdue30Plus; }
        public void setOverdue30Plus(BigDecimal overdue30Plus) { this.overdue30Plus = overdue30Plus; }
        public BigDecimal getOverdue60Plus() { return overdue60Plus; }
        public void setOverdue60Plus(BigDecimal overdue60Plus) { this.overdue60Plus = overdue60Plus; }
        public BigDecimal getOverdue90Plus() { return overdue90Plus; }
        public void setOverdue90Plus(BigDecimal overdue90Plus) { this.overdue90Plus = overdue90Plus; }
        public BigDecimal getOverdue0PlusRate() { return overdue0PlusRate; }
        public void setOverdue0PlusRate(BigDecimal overdue0PlusRate) { this.overdue0PlusRate = overdue0PlusRate; }
        public BigDecimal getOverdue30PlusRate() { return overdue30PlusRate; }
        public void setOverdue30PlusRate(BigDecimal overdue30PlusRate) { this.overdue30PlusRate = overdue30PlusRate; }
        public BigDecimal getOverdue60PlusRate() { return overdue60PlusRate; }
        public void setOverdue60PlusRate(BigDecimal overdue60PlusRate) { this.overdue60PlusRate = overdue60PlusRate; }
        public BigDecimal getOverdue90PlusRate() { return overdue90PlusRate; }
        public void setOverdue90PlusRate(BigDecimal overdue90PlusRate) { this.overdue90PlusRate = overdue90PlusRate; }

        @Override
        public String toString() {
            return String.format("Vintage %s: 初始金额=%.2f, 0+逾期率=%.2f%%, 30+逾期率=%.2f%%, 60+逾期率=%.2f%%, 90+逾期率=%.2f%%",
                    vintage, initialAmount, overdue0PlusRate, overdue30PlusRate, overdue60PlusRate, overdue90PlusRate);
        }
    }

    /**
     * 订单数据包（用于多线程传递数据）
     */
    public static class OrderDataPackage {
        private List<CustomerInfo> customers;
        private List<CustomerOrder> orders;
        private List<CustomerRepayPlan> repayPlans;
        private BigDecimal totalLoanAmount;
        private BigDecimal totalOutstandingAmount;
        private BigDecimal haohanOutstandingAmount;
        private int orderCount;

        public OrderDataPackage() {
            this.customers = new ArrayList<>();
            this.orders = new ArrayList<>();
            this.repayPlans = new ArrayList<>();
            this.totalLoanAmount = BigDecimal.ZERO;
            this.totalOutstandingAmount = BigDecimal.ZERO;
            this.haohanOutstandingAmount = BigDecimal.ZERO;
            this.orderCount = 0;
        }

        // Getters and Setters
        public List<CustomerInfo> getCustomers() { return customers; }
        public void setCustomers(List<CustomerInfo> customers) { this.customers = customers; }

        public List<CustomerOrder> getOrders() { return orders; }
        public void setOrders(List<CustomerOrder> orders) { this.orders = orders; }

        public List<CustomerRepayPlan> getRepayPlans() { return repayPlans; }
        public void setRepayPlans(List<CustomerRepayPlan> repayPlans) { this.repayPlans = repayPlans; }

        public BigDecimal getTotalLoanAmount() { return totalLoanAmount; }
        public void setTotalLoanAmount(BigDecimal totalLoanAmount) { this.totalLoanAmount = totalLoanAmount; }

        public BigDecimal getTotalOutstandingAmount() { return totalOutstandingAmount; }
        public void setTotalOutstandingAmount(BigDecimal totalOutstandingAmount) { this.totalOutstandingAmount = totalOutstandingAmount; }

        public BigDecimal getHaohanOutstandingAmount() { return haohanOutstandingAmount; }
        public void setHaohanOutstandingAmount(BigDecimal haohanOutstandingAmount) { this.haohanOutstandingAmount = haohanOutstandingAmount; }

        public int getOrderCount() { return orderCount; }
        public void setOrderCount(int orderCount) { this.orderCount = orderCount; }
    }

    /**
     * 数据生成结果类
     */
    public static class DataGenerationResult {
        private List<CustomerInfo> customers;
        private List<CustomerOrder> orders;
        private List<CustomerRepayPlan> repayPlans;

        // Getters and Setters
        public List<CustomerInfo> getCustomers() { return customers; }
        public void setCustomers(List<CustomerInfo> customers) { this.customers = customers; }
        public List<CustomerOrder> getOrders() { return orders; }
        public void setOrders(List<CustomerOrder> orders) { this.orders = orders; }
        public List<CustomerRepayPlan> getRepayPlans() { return repayPlans; }
        public void setRepayPlans(List<CustomerRepayPlan> repayPlans) { this.repayPlans = repayPlans; }
    }

    /**
     * 生成脱敏手机号
     */
    private static String generateMaskedPhone() {
        String[] prefixes = {"130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
                "150", "151", "152", "153", "155", "156", "157", "158", "159",
                "180", "181", "182", "183", "184", "185", "186", "187", "188", "189","199"};

        String prefix = prefixes[random.nextInt(prefixes.length)];

        // 生成后4位数字
        String lastFour = String.format("%04d", random.nextInt(10000));

        // 脱敏格式：186****6454
        return prefix + "****" + lastFour;
    }

    /**
     * 生成脱敏身份证号
     */
    private static String generateMaskedIdNo(String fullCode, String gender) {
        // 使用完整的6位行政区划代码
//        String fullCode = CITY_CODE_MAP.getOrDefault(city, "110000"); // 默认北京

        // 截取前4位
        String prefix = fullCode.substring(0, 4);

        // 生成倒数第二位数字（根据性别：男性单数，女性双数）
        int secondLastDigit;
        if ("男".equals(gender)) {
            // 男性：生成单数（1,3,5,7,9）
            secondLastDigit = 1 + random.nextInt(5) * 2; // 1,3,5,7,9
        } else {
            // 女性：生成双数（0,2,4,6,8）
            secondLastDigit = random.nextInt(5) * 2; // 0,2,4,6,8
        }

        // 生成最后一位数字（0-9）
        int lastDigit = random.nextInt(10);

        // 生成倒数第三位数字（0-9）
        int thirdLastDigit = random.nextInt(10);

        // 生成倒数第四位数字（0-9）
        int fourthLastDigit = random.nextInt(10);

        // 组合后4位数字
        String lastFour = String.format("%d%d%d%d", fourthLastDigit, thirdLastDigit, secondLastDigit, lastDigit);

        // 脱敏格式：513822**********0061
        return prefix + "**********" + lastFour;
    }

    /**
     * 生成订单号
     */
    private static String generateOrderNo() {
        return "ORD" + System.currentTimeMillis() + String.format("%04d", random.nextInt(10000));
    }

    private void insertCustomers(List<CustomerInfo> customers) {
        customerInfoService.saveBatch(customers);
    }

    /**
     * 插入客户订单
     */
    private void insertOrders(List<CustomerOrder> orders) {
        customerOrderService.saveBatch(orders);
    }

    /**
     * 插入客户还款计划
     */
    private void insertRepayPlans(List<CustomerRepayPlan> repayPlans) {
        customerRepayPlanService.saveBatch(repayPlans);
    }

    /**
     * 分批插入客户信息，避免连接超时
     */
    private void insertCustomersInBatches(List<CustomerInfo> customers) {
        if (customers.isEmpty()) return;

        int batchSize = 500; // 减小批次大小
        for (int i = 0; i < customers.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, customers.size());
            List<CustomerInfo> batch = customers.subList(i, endIndex);
            try {
                customerInfoService.saveBatch(batch);
                log.debug("插入客户信息批次 {}-{}", i, endIndex - 1);
            } catch (Exception e) {
                log.error("插入客户信息批次 {}-{} 失败", i, endIndex - 1, e);
                throw e;
            }
        }
    }

    /**
     * 分批插入订单，避免连接超时
     */
    private void insertOrdersInBatches(List<CustomerOrder> orders) {
        if (orders.isEmpty()) return;

        int batchSize = 500; // 减小批次大小
        for (int i = 0; i < orders.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, orders.size());
            List<CustomerOrder> batch = orders.subList(i, endIndex);
            try {
                customerOrderService.saveBatch(batch);
                log.debug("插入订单批次 {}-{}", i, endIndex - 1);
            } catch (Exception e) {
                log.error("插入订单批次 {}-{} 失败", i, endIndex - 1, e);
                throw e;
            }
        }
    }

    /**
     * 分批插入还款计划，避免连接超时
     */
    private void insertRepayPlansInBatches(List<CustomerRepayPlan> repayPlans) {
        if (repayPlans.isEmpty()) return;

        int batchSize = 1000; // 还款计划数量通常较多，可以适当增大批次
        for (int i = 0; i < repayPlans.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, repayPlans.size());
            List<CustomerRepayPlan> batch = repayPlans.subList(i, endIndex);
            try {
                customerRepayPlanService.saveBatch(batch);
                log.debug("插入还款计划批次 {}-{}", i, endIndex - 1);
            } catch (Exception e) {
                log.error("插入还款计划批次 {}-{} 失败", i, endIndex - 1, e);
                throw e;
            }
        }
    }
    // 随机获取一个城市和对应的代码
    public static Map.Entry<String, String> getRandomCityCode() {
        List<Map.Entry<String, String>> entries = new ArrayList<>(CITY_CODE_MAP.entrySet());
        if (entries.isEmpty()) {
            return null;
        }
        Random random = new Random();
        return entries.get(random.nextInt(entries.size()));
    }

    /**
     * 生成订单数据批次（多线程调用）
     */
    private OrderDataPackage generateOrderDataBatch(LocalDate month, int orderCount) {
        OrderDataPackage orderPackage = new OrderDataPackage();

        // 使用产品分布逻辑生成该月数据
        Map<String, Integer> productDistribution = calculateProductDistribution(month, orderCount);

        for (Map.Entry<String, Integer> entry : productDistribution.entrySet()) {
            String productName = entry.getKey();
            int productOrderCount = entry.getValue();

            for (int i = 0; i < productOrderCount; i++) {
                // 生成该月内随机的一天作为订单创建时间
                LocalDate randomDayInMonth = generateRandomDayInMonth(month);

                // 生成客户信息
                CustomerInfo customer = generateCustomerInfo(randomDayInMonth);

                // 生成订单（使用正确的产品名称和随机日期）
                CustomerOrder order = generateCustomerOrder(customer, randomDayInMonth, productName);
                order.setFrTime(customer.getCreatedTime().substring(0, 10));

                // 生成还款计划
                List<CustomerRepayPlan> repayPlans = generateRepayPlan(order);

                // 设置订单客户ID
                order.setCustomerId(customer.getId());

                // 添加到数据包
                orderPackage.getCustomers().add(customer);
                orderPackage.getOrders().add(order);
                orderPackage.getRepayPlans().addAll(repayPlans);

                // 更新统计
                orderPackage.setTotalLoanAmount(orderPackage.getTotalLoanAmount().add(order.getLoanAmount()));
                if ("未结清".equals(order.getStatus())) {
                    orderPackage.setTotalOutstandingAmount(orderPackage.getTotalOutstandingAmount().add(order.getRemainPayAmount()));
                    if ("浩瀚小贷".equals(order.getProductName())) {
                        orderPackage.setHaohanOutstandingAmount(orderPackage.getHaohanOutstandingAmount().add(order.getRemainPayAmount()));
                    }
                }
                orderPackage.setOrderCount(orderPackage.getOrderCount() + 1);
            }
        }

        return orderPackage;
    }

    /**
     * 处理批量插入（线程安全）
     */
    private synchronized void processBatchInsert(List<CustomerInfo> customerBatch,
                                                 List<CustomerOrder> orderBatch,
                                                 List<CustomerRepayPlan> repayPlanBatch,
                                                 AtomicInteger batchCount,
                                                 AtomicInteger totalProcessedOrders,
                                                 AtomicReference<BigDecimal> totalGeneratedAmount,
                                                 AtomicReference<BigDecimal> totalOutstandingAmount) {
        if (customerBatch.isEmpty()) {
            return;
        }

        int currentBatchCount = batchCount.incrementAndGet();
        log.info("开始批量插入第 {} 批数据，共 {} 条用户信息", currentBatchCount, customerBatch.size());

        long batchStartTime = System.currentTimeMillis();
        batchInsertDataBatch(new ArrayList<>(customerBatch), new ArrayList<>(orderBatch), new ArrayList<>(repayPlanBatch));
        long batchEndTime = System.currentTimeMillis();

        log.info("第 {} 批数据插入完成，耗时: {} 毫秒", currentBatchCount, (batchEndTime - batchStartTime));
        log.info("已处理 {} 条订单", totalProcessedOrders.get());
        log.info("当前总投放金额: {} 亿", totalGeneratedAmount.get().divide(new BigDecimal("100000000"), 2, RoundingMode.HALF_UP));
        log.info("当前在途余额: {} 亿", totalOutstandingAmount.get().divide(new BigDecimal("100000000"), 2, RoundingMode.HALF_UP));

        // 清空批量插入缓存
        customerBatch.clear();
        orderBatch.clear();
        repayPlanBatch.clear();
    }
}
